Index: source/graphics/MapReader.cpp
===================================================================
--- source/graphics/MapReader.cpp	(revision 18581)
+++ source/graphics/MapReader.cpp	(working copy)
@@ -358,7 +358,7 @@
 	VfsPath filename_xml = pathname.ChangeExtension(L".xml");
 
 	CXeromyces xmb_file;
-	if (xmb_file.Load(g_VFS, filename_xml, "scenario") != PSRETURN_OK)
+	if (xmb_file.Load(g_VFS, filename_xml, 0, "scenario") != PSRETURN_OK)
 		return PSRETURN_File_ReadFailed;
 
 	// Define all the relevant elements used in the XML file
@@ -467,7 +467,7 @@
 	// must only assign once, so do it here
 	node_idx = entity_idx = 0;
 
-	if (xmb_file.Load(g_VFS, xml_filename, "scenario") != PSRETURN_OK)
+	if (xmb_file.Load(g_VFS, xml_filename, 0, "scenario") != PSRETURN_OK)
 		throw PSERROR_File_ReadFailed();
 
 	// define the elements and attributes that are frequently used in the XML file,
Index: source/graphics/MaterialManager.cpp
===================================================================
--- source/graphics/MaterialManager.cpp	(revision 18581)
+++ source/graphics/MaterialManager.cpp	(working copy)
@@ -51,7 +51,7 @@
 		return iter->second;
 
 	CXeromyces xeroFile;
-	if (xeroFile.Load(g_VFS, pathname, "material") != PSRETURN_OK)
+	if (xeroFile.Load(g_VFS, pathname, 0, "material") != PSRETURN_OK)
 		return CMaterial();
 
 	#define EL(x) int el_##x = xeroFile.GetElementID(#x)
Index: source/graphics/ObjectBase.cpp
===================================================================
--- source/graphics/ObjectBase.cpp	(revision 18581)
+++ source/graphics/ObjectBase.cpp	(working copy)
@@ -211,7 +211,7 @@
 	m_UsedFiles.insert(pathname);
 
 	CXeromyces XeroFile;
-	if (XeroFile.Load(g_VFS, pathname, "actor") != PSRETURN_OK)
+	if (XeroFile.Load(g_VFS, pathname, 0, "actor") != PSRETURN_OK)
 		return false;
 
 	// Define all the elements used in the XML file
Index: source/graphics/ParticleEmitterType.cpp
===================================================================
--- source/graphics/ParticleEmitterType.cpp	(revision 18581)
+++ source/graphics/ParticleEmitterType.cpp	(working copy)
@@ -361,7 +361,7 @@
 	m_Texture = g_Renderer.GetTextureManager().GetErrorTexture();
 
 	CXeromyces XeroFile;
-	PSRETURN ret = XeroFile.Load(g_VFS, path, "particle");
+	PSRETURN ret = XeroFile.Load(g_VFS, path, 0, "particle");
 	if (ret != PSRETURN_OK)
 		return false;
 
Index: source/graphics/TerrainProperties.cpp
===================================================================
--- source/graphics/TerrainProperties.cpp	(revision 18581)
+++ source/graphics/TerrainProperties.cpp	(working copy)
@@ -46,7 +46,7 @@
 CTerrainPropertiesPtr CTerrainProperties::FromXML(const CTerrainPropertiesPtr& parent, const VfsPath& pathname)
 {
 	CXeromyces XeroFile;
-	if (XeroFile.Load(g_VFS, pathname, "terrain") != PSRETURN_OK)
+	if (XeroFile.Load(g_VFS, pathname, 0, "terrain") != PSRETURN_OK)
 		return CTerrainPropertiesPtr();
 
 	XMBElement root = XeroFile.GetRoot();
Index: source/graphics/TerrainTextureEntry.cpp
===================================================================
--- source/graphics/TerrainTextureEntry.cpp	(revision 18581)
+++ source/graphics/TerrainTextureEntry.cpp	(working copy)
@@ -45,7 +45,7 @@
 	ENSURE(properties);
 	
 	CXeromyces XeroFile;
-	if (XeroFile.Load(g_VFS, path, "terrain_texture") != PSRETURN_OK)
+	if (XeroFile.Load(g_VFS, path, 0, "terrain_texture") != PSRETURN_OK)
 	{
 		LOGERROR("Terrain xml not found (%s)", path.string8());
 		return;
Index: source/graphics/TextureConverter.cpp
===================================================================
--- source/graphics/TextureConverter.cpp	(revision 18581)
+++ source/graphics/TextureConverter.cpp	(working copy)
@@ -96,7 +96,7 @@
 CTextureConverter::SettingsFile* CTextureConverter::LoadSettings(const VfsPath& path) const
 {
 	CXeromyces XeroFile;
-	if (XeroFile.Load(m_VFS, path, "texture") != PSRETURN_OK)
+	if (XeroFile.Load(m_VFS, path, 0, "texture") != PSRETURN_OK)
 		return NULL;
 
 	// Define all the elements used in the XML file
Index: source/gui/CGUI.cpp
===================================================================
--- source/gui/CGUI.cpp	(revision 18581)
+++ source/gui/CGUI.cpp	(working copy)
@@ -849,7 +849,7 @@
 	Paths.insert(Filename);
 
 	CXeromyces XeroFile;
-	if (XeroFile.Load(g_VFS, Filename, "gui") != PSRETURN_OK)
+	if (XeroFile.Load(g_VFS, Filename, 0, "gui") != PSRETURN_OK)
 		return;
 
 	XMBElement node = XeroFile.GetRoot();
@@ -1165,7 +1165,7 @@
 				Paths.insert(filename);
 
 				CXeromyces XeroIncluded;
-				if (XeroIncluded.Load(g_VFS, filename, "gui") != PSRETURN_OK)
+				if (XeroIncluded.Load(g_VFS, filename, 0, "gui") != PSRETURN_OK)
 				{
 					LOGERROR("GUI: Error reading included XML: '%s'", utf8_from_wstring(filename));
 					continue;
@@ -1202,7 +1202,7 @@
 					// one might use the same parts of the GUI in different situations
 					Paths.insert(path);
 					CXeromyces XeroIncluded;
-					if (XeroIncluded.Load(g_VFS, path, "gui") != PSRETURN_OK)
+					if (XeroIncluded.Load(g_VFS, path, 0, "gui") != PSRETURN_OK)
 					{
 						LOGERROR("GUI: Error reading included XML: '%s'", path.string8());
 						continue;
Index: source/gui/GUIManager.cpp
===================================================================
--- source/gui/GUIManager.cpp	(revision 18581)
+++ source/gui/GUIManager.cpp	(working copy)
@@ -198,7 +198,7 @@
 	page.inputs.insert(path);
 
 	CXeromyces xero;
-	if (xero.Load(g_VFS, path, "gui_page") != PSRETURN_OK)
+	if (xero.Load(g_VFS, path, 0, "gui_page") != PSRETURN_OK)
 		// Fail silently (Xeromyces reported the error)
 		return;
 
Index: source/lib/file/vfs/vfs.cpp
===================================================================
--- source/lib/file/vfs/vfs.cpp	(revision 18581)
+++ source/lib/file/vfs/vfs.cpp	(working copy)
@@ -113,7 +113,7 @@
 			fileInfos->reserve(files.size());
 			for(VfsDirectory::VfsFiles::const_iterator it = files.begin(); it != files.end(); ++it)
 			{
-				const VfsFile& file = it->second;
+				const VfsFile& file = it->second[0];
 				fileInfos->push_back(CFileInfo(file.Name(), file.Size(), file.MTime()));
 			}
 		}
Index: source/lib/file/vfs/vfs_tree.cpp
===================================================================
--- source/lib/file/vfs/vfs_tree.cpp	(revision 18581)
+++ source/lib/file/vfs/vfs_tree.cpp	(working copy)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013 Wildfire Games
+/* Copyright (c) 2016 Wildfire Games
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -52,13 +52,7 @@
 
 static bool ShouldReplaceWith(const VfsFile& previousFile, const VfsFile& newFile)
 {
-	// 1) priority (override mods)
-	if(newFile.Priority() < previousFile.Priority())
-		return false;
-	if(newFile.Priority() > previousFile.Priority())
-		return true;
-
-	// 2) timestamp
+	// 1) timestamp
 	{
 		const double howMuchNewer = difftime(newFile.MTime(), previousFile.MTime());
 		const double threshold = 2.0;	// FAT timestamp resolution [seconds]
@@ -70,7 +64,7 @@
 		// mtime resolution)
 	}
 
-	// 3) precedence (efficiency of file provider)
+	// 2) precedence (efficiency of file provider)
 	if(newFile.Loader()->Precedence() < previousFile.Loader()->Precedence())
 		return false;
 
@@ -80,21 +74,26 @@
 
 VfsFile* VfsDirectory::AddFile(const VfsFile& file)
 {
-	std::pair<VfsPath, VfsFile> value = std::make_pair(file.Name(), file);
-	std::pair<VfsFiles::iterator, bool> ret = m_files.insert(value);
-	if(!ret.second)	// already existed
+	std::vector<VfsFile>& fileList = m_files[file.Name()];
+	for (size_t i = 0; i < fileList.size(); ++i)
 	{
-		VfsFile& previousFile = ret.first->second;
-		const VfsFile& newFile = value.second;
-		if(ShouldReplaceWith(previousFile, newFile))
-			previousFile = newFile;
+		VfsFile previousFile = fileList[i];
+		if (previousFile.Priority() == file.Priority())
+		{
+			if (ShouldReplaceWith(previousFile, file))
+				fileList[i] = file;
+			return &fileList[i];
+		}
+		else if (previousFile.Priority() <= file.Priority())
+		{
+			fileList.emplace(fileList.begin() + i, file);
+			stats_vfs_file_add(file.Size());
+			return &fileList[i];
+		}
 	}
-	else
-	{
-		stats_vfs_file_add(file.Size());
-	}
-
-	return &(*ret.first).second;
+	fileList.push_back(file);
+	stats_vfs_file_add(file.Size());
+	return &fileList.back();
 }
 
 
@@ -117,9 +116,9 @@
 VfsFile* VfsDirectory::GetFile(const VfsPath& name)
 {
 	VfsFiles::iterator it = m_files.find(name.string());
-	if(it == m_files.end())
+	if(it == m_files.end() || it->second.empty())
 		return 0;
-	return &it->second;
+	return &it->second[0];
 }
 
 
@@ -185,7 +184,7 @@
 	const std::wstring indentation(4*indentLevel, ' ');
 	for(VfsDirectory::VfsFiles::const_iterator it = files.begin(); it != files.end(); ++it)
 	{
-		const VfsFile& file = it->second;
+		const VfsFile& file = it->second[0];
 		descriptions += indentation;
 		descriptions += FileDescription(file);
 		descriptions += L"\n";
Index: source/lib/file/vfs/vfs_tree.h
===================================================================
--- source/lib/file/vfs/vfs_tree.h	(revision 18581)
+++ source/lib/file/vfs/vfs_tree.h	(working copy)
@@ -78,7 +78,7 @@
 class VfsDirectory
 {
 public:
-	typedef std::map<VfsPath, VfsFile> VfsFiles;
+	typedef std::map<VfsPath, std::vector<VfsFile>> VfsFiles;
 	typedef std::map<VfsPath, VfsDirectory> VfsSubdirectories;
 
 	VfsDirectory();
Index: source/ps/TemplateLoader.cpp
===================================================================
--- source/ps/TemplateLoader.cpp	(revision 18581)
+++ source/ps/TemplateLoader.cpp	(working copy)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015 Wildfire Games.
+/* Copyright (C) 2016 Wildfire Games.
  * This file is part of 0 A.D.
  *
  * 0 A.D. is free software: you can redistribute it and/or modify
@@ -30,7 +30,9 @@
 static CParamNode NULL_NODE(false);
 
 
-bool CTemplateLoader::LoadTemplateFile(const std::string& templateName, int depth)
+
+
+bool CTemplateLoader::LoadTemplateFile(const std::string& templateName, size_t modPriorityLevel, int depth)
 {
 	// If this file was already loaded, we don't need to do anything
 	if (m_TemplateFileData.find(templateName) != m_TemplateFileData.end())
@@ -55,7 +57,7 @@
 	{
 		// Load the base entity template, if it wasn't already loaded
 		std::string baseName = templateName.substr(8);
-		if (!LoadTemplateFile(baseName, depth+1))
+		if (!LoadTemplateFile(baseName, 0, depth + 1))
 		{
 			LOGERROR("Failed to load entity template '%s'", baseName.c_str());
 			return false;
@@ -70,7 +72,7 @@
 	{
 		// Load the base entity template, if it wasn't already loaded
 		std::string baseName = templateName.substr(7);
-		if (!LoadTemplateFile(baseName, depth+1))
+		if (!LoadTemplateFile(baseName, 0, depth + 1))
 		{
 			LOGERROR("Failed to load entity template '%s'", baseName.c_str());
 			return false;
@@ -85,7 +87,7 @@
 	{
 		// Load the base entity template, if it wasn't already loaded
 		std::string baseName = templateName.substr(7);
-		if (!LoadTemplateFile(baseName, depth+1))
+		if (!LoadTemplateFile(baseName, 0, depth + 1))
 		{
 			LOGERROR("Failed to load entity template '%s'", baseName.c_str());
 			return false;
@@ -100,7 +102,7 @@
 	{
 		// Load the base entity template, if it wasn't already loaded
 		std::string baseName = templateName.substr(11);
-		if (!LoadTemplateFile(baseName, depth+1))
+		if (!LoadTemplateFile(baseName, 0, depth + 1))
 		{
 			LOGERROR("Failed to load entity template '%s'", baseName.c_str());
 			return false;
@@ -115,7 +117,7 @@
 	{
 		// Load the base entity template, if it wasn't already loaded
 		std::string baseName = templateName.substr(13);
-		if (!LoadTemplateFile(baseName, depth+1))
+		if (!LoadTemplateFile(baseName, 0, depth + 1))
 		{
 			LOGERROR("Failed to load entity template '%s'", baseName.c_str());
 			return false;
@@ -130,7 +132,7 @@
 	{
 		// Load the base entity template, if it wasn't already loaded
 		std::string baseName = templateName.substr(9);
-		if (!LoadTemplateFile(baseName, depth+1))
+		if (!LoadTemplateFile(baseName, 0, depth + 1))
 		{
 			LOGERROR("Failed to load entity template '%s'", baseName.c_str());
 			return false;
@@ -144,9 +146,9 @@
 
 	VfsPath path = VfsPath(TEMPLATE_ROOT) / wstring_from_utf8(templateName + ".xml");
 	CXeromyces xero;
-	PSRETURN ok = xero.Load(g_VFS, path);
+	PSRETURN ok = xero.Load(g_VFS, path, modPriorityLevel);
 	if (ok != PSRETURN_OK)
-		return false; // (Xeromyces already logged an error with the full filename)
+		return false; // Xeromyces already logged an error with the full filename
 
 	int attr_parent = xero.GetAttributeID("parent");
 	CStr parentName = xero.GetRoot().GetAttributes().GetNamedItem(attr_parent);
@@ -159,17 +161,29 @@
 			return false;
 		}
 
-		// Ensure the parent is loaded
-		if (!LoadTemplateFile(parentName, depth+1))
+		if (parentName == "MOD")
 		{
-			LOGERROR("Failed to load parent '%s' of entity template '%s'", parentName.c_str(), templateName.c_str());
-			return false;
+			// Ensure the parent is loaded
+			if (!LoadTemplateFile(templateName, modPriorityLevel + 1, depth))
+			{
+				LOGERROR("Failed to load parent from lower priority mod of entity template '%s'", templateName.c_str());
+				return false;
+			}
 		}
+		else
+		{
+			// Ensure the parent is loaded
+			if (!LoadTemplateFile(parentName, 0, depth + 1))
+			{
+				LOGERROR("Failed to load parent '%s' of entity template '%s'", parentName.c_str(), templateName.c_str());
+				return false;
+			}
 
-		CParamNode& parentData = m_TemplateFileData[parentName];
+			CParamNode& parentData = m_TemplateFileData[parentName];
 
-		// Initialise this template with its parent
-		m_TemplateFileData[templateName] = parentData;
+			// Initialise this template with its parent
+			m_TemplateFileData[templateName] = parentData;
+		}
 	}
 
 	// Load the new file into the template data (overriding parent values)
@@ -330,7 +344,7 @@
 const CParamNode& CTemplateLoader::GetTemplateFileData(const std::string& templateName)
 {
 	// Load the template if necessary
-	if (!LoadTemplateFile(templateName, 0))
+	if (!LoadTemplateFile(templateName, 0, 0))
 	{
 		LOGERROR("Failed to load entity template '%s'", templateName.c_str());
 		return NULL_NODE;
@@ -343,7 +357,7 @@
 {
 	// Load the base actor template if necessary
 	const char* templateName = "special/actor";
-	if (!LoadTemplateFile(templateName, 0))
+	if (!LoadTemplateFile(templateName, 0, 0))
 	{
 		LOGERROR("Failed to load entity template '%s'", templateName);
 		return;
Index: source/ps/TemplateLoader.h
===================================================================
--- source/ps/TemplateLoader.h	(revision 18581)
+++ source/ps/TemplateLoader.h	(working copy)
@@ -73,8 +73,10 @@
 	 * and saves into m_TemplateFileData. Also loads any parents that are not yet
 	 * loaded. Returns false on error.
 	 * @param templateName XML filename to load (not a |-separated string)
+	 * @param modPriorityLevel mod to load the file from, 0 for the highest priority mod
+	 * @param depth counter to prevent infinite loops, initialise to 0
 	 */
-	bool LoadTemplateFile(const std::string& templateName, int depth);
+	bool LoadTemplateFile(const std::string& templateName, size_t modPriorityLevel, int depth);
 
 	/**
 	 * Constructs a standard static-decorative-object template for the given actor
Index: source/ps/XML/Xeromyces.cpp
===================================================================
--- source/ps/XML/Xeromyces.cpp	(revision 18581)
+++ source/ps/XML/Xeromyces.cpp	(working copy)
@@ -107,7 +107,7 @@
 	return g_ValidatorCache.find(name)->second;
 }
 
-PSRETURN CXeromyces::Load(const PIVFS& vfs, const VfsPath& filename, const std::string& validatorName /* = "" */)
+PSRETURN CXeromyces::Load(const PIVFS& vfs, const VfsPath& filename, size_t modPriorityLevel, const std::string& validatorName /* = "" */)
 {
 	ENSURE(g_XeromycesStarted);
 
@@ -147,7 +147,7 @@
 	return ConvertFile(vfs, filename, xmbPath, validatorName);
 }
 
-bool CXeromyces::GenerateCachedXMB(const PIVFS& vfs, const VfsPath& sourcePath, VfsPath& archiveCachePath, const std::string& validatorName /* = "" */)
+bool CXeromyces::GenerateCachedXMB(const PIVFS& vfs, const VfsPath& sourcePath, VfsPath& archiveCachePath, size_t modPriorityLevel, const std::string& validatorName /* = "" */)
 {
 	CCacheLoader cacheLoader(vfs, L".xmb");
 
Index: source/ps/XML/Xeromyces.h
===================================================================
--- source/ps/XML/Xeromyces.h	(revision 18581)
+++ source/ps/XML/Xeromyces.h	(working copy)
@@ -46,7 +46,7 @@
 	/**
 	 * Load from an XML file (with invisible XMB caching).
 	 */
-	PSRETURN Load(const PIVFS& vfs, const VfsPath& filename, const std::string& validatorName = "");
+	PSRETURN Load(const PIVFS& vfs, const VfsPath& filename, size_t modPriorityLevel = 0, const std::string& validatorName = "");
 
 	/**
 	 * Load from an in-memory XML string (with no caching).
@@ -58,7 +58,7 @@
 	 * Returns the XMB path in @p archiveCachePath.
 	 * Returns false on error.
 	 */
-	bool GenerateCachedXMB(const PIVFS& vfs, const VfsPath& sourcePath, VfsPath& archiveCachePath, const std::string& validatorName = "");
+	bool GenerateCachedXMB(const PIVFS& vfs, const VfsPath& sourcePath, VfsPath& archiveCachePath, size_t modPriorityLevel = 0, const std::string& validatorName = "");
 
 	/**
 	 * Call once when initialising the program, to load libxml2.
Index: source/simulation2/system/ParamNode.cpp
===================================================================
--- source/simulation2/system/ParamNode.cpp	(revision 18581)
+++ source/simulation2/system/ParamNode.cpp	(working copy)
@@ -45,7 +45,7 @@
 void CParamNode::LoadXML(CParamNode& ret, const VfsPath& path, const std::string& validatorName)
 {
 	CXeromyces xero;
-	PSRETURN ok = xero.Load(g_VFS, path, validatorName);
+	PSRETURN ok = xero.Load(g_VFS, path, 0, validatorName);
 	if (ok != PSRETURN_OK)
 		return; // (Xeromyces already logged an error)
 
Index: source/soundmanager/scripting/SoundGroup.cpp
===================================================================
--- source/soundmanager/scripting/SoundGroup.cpp	(revision 18581)
+++ source/soundmanager/scripting/SoundGroup.cpp	(working copy)
@@ -283,7 +283,7 @@
 bool CSoundGroup::LoadSoundGroup(const VfsPath& pathnameXML)
 {
 	CXeromyces XeroFile;
-	if (XeroFile.Load(g_VFS, pathnameXML, "sound_group") != PSRETURN_OK)
+	if (XeroFile.Load(g_VFS, pathnameXML, 0, "sound_group") != PSRETURN_OK)
 	{
 		HandleError(L"error loading file", pathnameXML, ERR::FAIL);
 		return false;
