diff --git a/Build/SlimDX.dll b/Build/SlimDX.dll
index ca05cbd716feae38ae43f2f25f5cb870ac574390..c02903f6e1326ca22b4663d9a187b5f290041acd 100755
Binary files a/Build/SlimDX.dll and b/Build/SlimDX.dll differ
diff --git a/Build/Updater.ini b/Build/Updater.ini
index 688eb2eaa2eb02afd5d6d5c16ff30cd48c09d2f8..fe4d499e58f216c92d86437a32e75c25ebe2dd02 100755
--- a/Build/Updater.ini
+++ b/Build/Updater.ini
@@ -1,4 +1,4 @@
 URL http://devbuilds.drdteam.org/gzdbbf/
 FileName Builder.exe
-UpdateName GZDoom_Builder_Bugfix-r[REVNUM]-x64.7z
-UpdaterName GZDB_Updater-x64.7z
\ No newline at end of file
+UpdateName GZDoom_Builder_Bugfix-r[REVNUM].7z
+UpdaterName GZDB_Updater-x86.7z
\ No newline at end of file
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index 6bcf4ad220cc481cdf5aace9e830a9912f936dc3..d3d921e66bfab64f5e2139acc153f83ba25001d4 100755
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -2287,6 +2287,24 @@ namespace CodeImp.DoomBuilder.Data
                 }
             }
         }
+
+        // This loads MODELDEF data from a specific file or lump name
+        private void LoadModeldefFromLocation(ModeldefParser parser, string location)
+        {
+            IEnumerable<TextResourceData> streams = currentreader.GetModeldefData(location);
+            foreach (TextResourceData data in streams)
+            {
+                // Parse this data
+                parser.Parse(data, false);
+
+                //mxd. DECORATE lumps are interdepandable. Can't carry on...
+                if (parser.HasError)
+                {
+                    parser.LogError();
+                    return;
+                }
+            }
+        }
 		
 		// This gets thing information by index
 		public ThingTypeInfo GetThingInfo(int thingtype)
@@ -2407,7 +2425,7 @@ namespace CodeImp.DoomBuilder.Data
 			// Abort if no classnames are defined in DECORATE or game config...
 			if(actorsbyclass.Count == 0) return;
 
-			ModeldefParser parser = new ModeldefParser(actorsbyclass);
+			ModeldefParser parser = new ModeldefParser(actorsbyclass) { OnInclude = LoadModeldefFromLocation };
 			foreach(DataReader dr in containers)
 			{
 				currentreader = dr;
diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs
index df6264cb0cb9e1d8822c48e122bc6269dccd40e3..a435c7ab44cc6139cee949cee8f7324f4e1924d7 100755
--- a/Source/Core/Data/DataReader.cs
+++ b/Source/Core/Data/DataReader.cs
@@ -239,6 +239,9 @@ namespace CodeImp.DoomBuilder.Data
         // [ZZ] When implemented, this returns ZSCRIPT lumps
         public abstract IEnumerable<TextResourceData> GetZScriptData(string pname);
 
+        // [ZZ] When implemented, this returns MODELDEF lumps
+        public abstract IEnumerable<TextResourceData> GetModeldefData(string pname);
+
         //mxd. When implemented, this returns MAPINFO lumps
         public abstract IEnumerable<TextResourceData> GetMapinfoData();
 
diff --git a/Source/Core/Data/PK3StructuredReader.cs b/Source/Core/Data/PK3StructuredReader.cs
index dc48e7127169729cc84d67292956c21882970b06..0c584725a7f1e6330360f43fe861b8858e958a99 100755
--- a/Source/Core/Data/PK3StructuredReader.cs
+++ b/Source/Core/Data/PK3StructuredReader.cs
@@ -572,6 +572,50 @@ namespace CodeImp.DoomBuilder.Data
 
         #endregion
 
+        #region ================== MODELDEF
+
+        // This finds and returns MODELDEF streams
+        public override IEnumerable<TextResourceData> GetModeldefData(string pname)
+        {
+            // Error when suspended
+            if (issuspended) throw new Exception("Data reader is suspended");
+
+            List<TextResourceData> result = new List<TextResourceData>();
+            string[] allfilenames;
+
+            // Find in root directory
+            string filename = Path.GetFileName(pname);
+            string pathname = Path.GetDirectoryName(pname);
+
+            if (filename.IndexOf('.') > -1)
+            {
+                string fullname = Path.Combine(pathname, filename);
+                if (FileExists(fullname))
+                {
+                    allfilenames = new string[1];
+                    allfilenames[0] = Path.Combine(pathname, filename);
+                }
+                else
+                {
+                    allfilenames = new string[0];
+                    General.ErrorLogger.Add(ErrorType.Warning, "Unable to load MODELDEF file \"" + fullname + "\"");
+                }
+            }
+            else
+                allfilenames = GetAllFilesWithTitle(pathname, filename, false);
+
+            foreach (string foundfile in allfilenames)
+                result.Add(new TextResourceData(this, LoadFile(foundfile), foundfile, true));
+
+            // Find in any of the wad files
+            for (int i = wads.Count - 1; i >= 0; i--)
+                result.AddRange(wads[i].GetModeldefData(pname));
+
+            return result;
+        }
+
+        #endregion
+
         #region ================== VOXELDEF (mxd)
 
         //mxd. This returns the list of voxels, which can be used without VOXELDEF definition
diff --git a/Source/Core/Data/WADReader.cs b/Source/Core/Data/WADReader.cs
index ddee2c4488f4cf28ce4d3556d6d57388f0d8583c..cf7d2ae9fea1b3fe393b5087a45d09299f21c241 100755
--- a/Source/Core/Data/WADReader.cs
+++ b/Source/Core/Data/WADReader.cs
@@ -1047,6 +1047,20 @@ namespace CodeImp.DoomBuilder.Data
             return new List<TextResourceData> { result[result.Count - 1] };
         }
 
+        // [ZZ] This finds and returns MODELDEF streams
+        public override IEnumerable<TextResourceData> GetModeldefData(string pname)
+        {
+            if (issuspended) throw new Exception("Data reader is suspended");
+            List<TextResourceData> result = GetAllLumpsData(pname); //mxd
+
+            //mxd. Return ALL DECORATE lumps
+            if (result.Count == 0 || string.Compare(pname, "MODELDEF", StringComparison.OrdinalIgnoreCase) == 0)
+                return result;
+
+            //mxd. Return THE LAST include lump, because that's the way ZDoom seems to operate
+            return new List<TextResourceData> { result[result.Count - 1] };
+        }
+
         //mxd. Should be only one entry per wad
         public override IEnumerable<TextResourceData> GetMapinfoData() 
 		{
diff --git a/Source/Core/Properties/AssemblyInfo.cs b/Source/Core/Properties/AssemblyInfo.cs
index 205e95d0b3fdf381e8f1c3617d2b03dd777c79b3..700e47ddebacd282304d71c6194be525975f0fde 100755
--- a/Source/Core/Properties/AssemblyInfo.cs
+++ b/Source/Core/Properties/AssemblyInfo.cs
@@ -30,6 +30,6 @@ using CodeImp.DoomBuilder;
 //      Build Number
 //      Revision
 //
-[assembly: AssemblyVersion("2.3.0.3028")]
+[assembly: AssemblyVersion("2.3.0.3029")]
 [assembly: NeutralResourcesLanguageAttribute("en")]
-[assembly: AssemblyHash("6768bc7")]
+[assembly: AssemblyHash("3c433cf")]
diff --git a/Source/Core/ZDoom/ModeldefParser.cs b/Source/Core/ZDoom/ModeldefParser.cs
index 2549074af5d10c9182e9527c8cc1f7ef7be879e4..a799d8572ecaa18a8b53e2fbf9b46d1a7b98b6d9 100755
--- a/Source/Core/ZDoom/ModeldefParser.cs
+++ b/Source/Core/ZDoom/ModeldefParser.cs
@@ -7,6 +7,8 @@ using CodeImp.DoomBuilder.Data;
 using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.GZBuilder.Data;
 using SlimDX;
+using System.IO;
+using System.Globalization;
 
 #endregion
 
@@ -14,16 +16,24 @@ namespace CodeImp.DoomBuilder.ZDoom
 {
 	internal class ModeldefParser : ZDTextParser
 	{
-		#region ================== Variables
+        public delegate void IncludeDelegate(ModeldefParser parser, string includefile);
 
-		private readonly Dictionary<string, int> actorsbyclass;
+        public IncludeDelegate OnInclude;
+
+
+        #region ================== Variables
+
+        private readonly Dictionary<string, int> actorsbyclass;
 		private Dictionary<string, ModelData> entries; //classname, entry
+        //mxd. Includes tracking
+        private HashSet<string> parsedlumps;
 
-		#endregion
 
-		#region ================== Properties
+        #endregion
+
+        #region ================== Properties
 
-		internal override ScriptType ScriptType { get { return ScriptType.MODELDEF; } }
+        internal override ScriptType ScriptType { get { return ScriptType.MODELDEF; } }
 		internal Dictionary<string, ModelData> Entries { get { return entries; } }
 
 		#endregion
@@ -34,6 +44,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 		{
 			this.actorsbyclass = actorsbyclass;
 			this.entries = new Dictionary<string, ModelData>(StringComparer.OrdinalIgnoreCase);
+            this.parsedlumps = new HashSet<string>();
 		}
 
 		#endregion
@@ -53,11 +64,88 @@ namespace CodeImp.DoomBuilder.ZDoom
 			// Cannot process?
 			if(!base.Parse(data, clearerrors)) return false;
 
-			// Continue until at the end of the stream
-			while(SkipWhitespace(true)) 
+            // Keep local data
+            Stream localstream = datastream;
+            string localsourcename = sourcename;
+            BinaryReader localreader = datareader;
+            DataLocation locallocation = datalocation; //mxd
+            string localtextresourcepath = textresourcepath; //mxd
+
+            // Continue until at the end of the stream
+            while (SkipWhitespace(true)) 
 			{
 				string token = ReadToken();
-				if(string.IsNullOrEmpty(token) || token.ToLowerInvariant() != "model") continue;
+
+				if(string.IsNullOrEmpty(token) || token.ToLowerInvariant() != "model")
+                {
+                    if (token != null && token.ToLowerInvariant() == "#include")
+                    {
+                        //INFO: ZDoom DECORATE include paths can't be relative ("../actor.txt") 
+                        //or absolute ("d:/project/actor.txt") 
+                        //or have backward slashes ("info\actor.txt")
+                        //include paths are relative to the first parsed entry, not the current one 
+                        //also include paths may or may not be quoted
+                        SkipWhitespace(true);
+                        string filename = StripQuotes(ReadToken(false)); //mxd. Don't skip newline
+
+                        //mxd. Sanity checks
+                        if (string.IsNullOrEmpty(filename))
+                        {
+                            ReportError("Expected file name to include");
+                            return false;
+                        }
+
+                        //mxd. Check invalid path chars
+                        if (!CheckInvalidPathChars(filename)) return false;
+
+                        //mxd. Absolute paths are not supported...
+                        if (Path.IsPathRooted(filename))
+                        {
+                            ReportError("Absolute include paths are not supported by ZDoom");
+                            return false;
+                        }
+
+                        //mxd. Relative paths are not supported
+                        if (filename.StartsWith(RELATIVE_PATH_MARKER) || filename.StartsWith(CURRENT_FOLDER_PATH_MARKER) ||
+                            filename.StartsWith(ALT_RELATIVE_PATH_MARKER) || filename.StartsWith(ALT_CURRENT_FOLDER_PATH_MARKER))
+                        {
+                            ReportError("Relative include paths are not supported by ZDoom");
+                            return false;
+                        }
+
+                        //mxd. Backward slashes are not supported
+                        if (filename.Contains(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture)))
+                        {
+                            ReportError("Only forward slashes are supported by ZDoom");
+                            return false;
+                        }
+
+                        //mxd. Already parsed?
+                        if (parsedlumps.Contains(filename))
+                        {
+                            ReportError("Already parsed \"" + filename + "\". Check your include directives");
+                            return false;
+                        }
+
+                        //mxd. Add to collection
+                        parsedlumps.Add(filename);
+
+                        // Callback to parse this file now
+                        if (OnInclude != null) OnInclude(this, filename);
+
+                        //mxd. Bail out on error
+                        if (this.HasError) return false;
+
+                        // Set our buffers back to continue parsing
+                        datastream = localstream;
+                        datareader = localreader;
+                        sourcename = localsourcename;
+                        datalocation = locallocation; //mxd
+                        textresourcepath = localtextresourcepath; //mxd
+                    }
+
+                    continue;
+                }
 
 				// Find classname
 				SkipWhitespace(true);
diff --git a/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs b/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
index f701399020daed201a069f65e9f1095e7e677da1..a2e2fca8bd0425f782c6b8817dd54591a55f223e 100755
--- a/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
+++ b/Source/Plugins/BuilderModes/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Resources;
 //      Build Number
 //      Revision
 //
-[assembly: AssemblyVersion("2.3.0.3028")]
+[assembly: AssemblyVersion("2.3.0.3029")]
 [assembly: NeutralResourcesLanguageAttribute("en")]
diff --git a/Source/Plugins/StairSectorBuilder/StairSectorBuilder.csproj b/Source/Plugins/StairSectorBuilder/StairSectorBuilder.csproj
index af0dcf67164dd2ba06197821aff7c5596b98c7e2..056ccfa87beda040287805c36f63e260bc5f8902 100755
--- a/Source/Plugins/StairSectorBuilder/StairSectorBuilder.csproj
+++ b/Source/Plugins/StairSectorBuilder/StairSectorBuilder.csproj
@@ -133,6 +133,7 @@
     <ProjectReference Include="..\..\Core\Builder.csproj">
       <Project>{818b3d10-f791-4c3f-9af5-bb2d0079b63c}</Project>
       <Name>Builder</Name>
+      <Private>False</Private>
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />