From d619dd60576a9300f1986c156dd98dad1b4c0c93 Mon Sep 17 00:00:00 2001
From: Tazpn <tazpn@users.sourceforge.net>
Date: Sun, 20 Aug 2006 00:34:05 +0000
Subject: [PATCH] 1. Fix issue with exporting with user version specified. 
 Oblivion CS will crash if not set correctly. 2. Fix issues with nif export in
 general around bhk ordering (ported over from gundalfs changes) 3. Civ4
 Shader support for max 4. Numerous bug fixes to max.

---
 MaxNifPlugins_Readme.txt           |  10 +-
 MaxNifTools.ini                    |  44 ++--
 NifCommon/AppSettings.cpp          |  18 ++
 NifCommon/AppSettings.h            |   3 +
 NifCommon/IniSection.h             | 124 +++++++++++
 NifCommon/NifCommon_VC80.vcproj    |   8 +
 NifCommon/niutils.cpp              |  89 +++++++-
 NifCommon/niutils.h                |  10 +-
 NifCommon/objectParams.h           |   5 +-
 NifExport/Coll.cpp                 |  29 +--
 NifExport/Config.cpp               |   7 +
 NifExport/Exporter.cpp             |  15 +-
 NifExport/Exporter.h               |   9 +-
 NifExport/Mesh.cpp                 |   7 +-
 NifExport/MtlTex.cpp               | 334 ++++++++++++++++++++++++++--
 NifExport/NifExport.cpp            | 105 ++++++++-
 NifExport/NifExport.rc             | 122 +++++++----
 NifExport/NifExport_VC80.vcproj    |  12 +-
 NifExport/Util.cpp                 |  10 +-
 NifExport/pch.h                    |   3 +-
 NifExport/resource.h               |  10 +-
 NifImport/ImportMeshAndSkin.cpp    |   2 +-
 NifImport/ImportMtlAndTex.cpp      | 213 +++++++++++++++++-
 NifImport/ImportSkeleton.cpp       |   5 +-
 NifImport/MaxNifImport.cpp         |  38 ----
 NifImport/MaxNifImport.rc          |  40 +++-
 NifImport/MaxNifImport_VC80.vcproj |   8 +-
 NifImport/NIFImport.cpp            | 119 ++++++----
 NifImport/NIFImporter.h            |  10 +-
 NifImport/NifDialog.cpp            | 187 ++++++++++++++++
 NifImport/objectParams.h           | 339 -----------------------------
 NifImport/resource.h               |  22 +-
 NifPlugins_VC80.sln                |   1 +
 33 files changed, 1380 insertions(+), 578 deletions(-)
 create mode 100644 NifCommon/IniSection.h
 create mode 100644 NifImport/NifDialog.cpp
 delete mode 100644 NifImport/objectParams.h

diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt
index 902dc78..971f29c 100644
--- a/MaxNifPlugins_Readme.txt
+++ b/MaxNifPlugins_Readme.txt
@@ -34,11 +34,15 @@
       - Added Vertex Color modifier support
       - Fixed issue with static animation import
       - Fixed issue with skin vertex weight count import
+      - Added support for more material/texture properties
+      - Added support for Civilization IV Shader, if installed
+        o holds much of the material data in nif compatible form
       
     o Exporter
       - Upgraded to Visual Studio 2005
       - Dropped registry support in favor of INI file.
-      - Dropped Official Max6 support because I do not have SDK to compile it with (try the max 7 files).
+      - Dropped Official Max6 support because I do not have Max 6 to compile it
+        o Try editing the MaxNifTools.ini and setting the MaxSDKVersion to 0x17700d00
       - Fixed issue with importing glossiness setting on textures.
       - Fixed issues with export of vertex color. Alpha map is now exported as part of the normal color map.
       - No longer exports meshes associated with bone or biped nodes.
@@ -46,6 +50,10 @@
       - Mass, Restitution(Ellasticity), and Friction now share values with Reactor(Havok)
       - Modified UPB export to actually export the values in the UserPropBuffer not just a fixed list.
       - Added Skin Modifier export
+      - Added support for more material/texture properties
+      - Added support for Civilization IV Shader, if installed
+        o holds much of the material data in nif compatible form
+      - Fixed issue with UV map needing to be flipped
       
     o NifProps Utility
       - Mass, Restitution(Ellasticity), and Friction now share values with Reactor(Havok)
diff --git a/MaxNifTools.ini b/MaxNifTools.ini
index c7b2529..74969fd 100644
--- a/MaxNifTools.ini
+++ b/MaxNifTools.ini
@@ -6,7 +6,7 @@
 ShortDescription=Netimmerse/Gamebryo
 ; KnownApplications - Used to indicate which sections in the ini file point 
 ;    to "Applications" which have their own settings in a section below.
-KnownApplications=Oblivion;Morrowind;Civ4;DAoC
+KnownApplications=Oblivion;Morrowind;Civilization 4;Dark Age of Camelot;User
 ; Reparse the Applications (and therefore Texture directory cache) on every import/export
 Reparse=0
 
@@ -24,14 +24,14 @@ GenerateStrips=1
 FurnatureMarkers=1
 ; Use Lights if present. Default:0
 Lights=0
-; Include Hidden Nodes if present. Default:0
-IncludeHidden=0
+; Include Hidden Nodes if present. Default:1
+IncludeHidden=1
 ; Export Collision meshes if present. Default:1
 ExportCollision=1
 ; Export Vertext Colors. Default:1
 VertexColors=1
-; Remap Indices. Default:1
-RemapIndices=1
+; Remap Indices. Default:0
+RemapIndices=0
 ; Texture Prefix if texture not found in AppSettings directory. Default:textures
 TexturePrefix=textures
 ; Add Export additional NiNodes for Meshes. Default: 0
@@ -40,14 +40,14 @@ ExportExtraNodes=0
 ExportSkin=1
 ; Export UserPropBuffer. Default: 0
 UserPropBuffer=0
-; Flatten Node Hierarchy. Default: 0
-FlattenHierarchy=0
-; Remove Unreferenced Bones. Default: 0
-RemoveUnreferencedBones=0
+; Flatten Node Hierarchy. Default: 1
+FlattenHierarchy=1
+; Remove Unreferenced Bones. Default: 1
+RemoveUnreferencedBones=1
 
 [MaxNifImport]
 ; Max SDK Plugin Version (0 - AutoSelect; 0x17700d00 - Max6, 0x1f401100 - Max8)  Default: 0 
-MaxSDKVersion=0x17700d00
+MaxSDKVersion=0
 ; Current Application to get setting/directory information from.  Should match KnownApps above or Auto.
 ;   Auto will check the import file against the known root paths use that app if a directory match is found.
 CurrentApp=Auto
@@ -64,7 +64,7 @@ EnableAutoSmooth=1
 ; AutoSmooth angle. Default: 30
 AutoSmoothAngle=30.0
 ; Remove Double/Illegal faces on meshes on import. Default:1
-RemoveDoubleFaces=1
+RemoveDegenerateFaces=1
 RemoveIllegalFaces=1
 ; EnableSkinSupport attempt to skin the mesh if bones are available. Default:1
 EnableSkinSupport=1
@@ -92,8 +92,6 @@ MaxBoneWidth=0.1
 BoneWidthToLengthRatio=0.01
 ; Force nub to point back to parent at expense of loss of rotation data. Default: 1
 ForceRotation=0
-; Browse for skeleton on import. Default: 1
-BrowseForSkeleton=1
 ; DefaultName for Skeletons (use if in same directory as imported nif)
 DefaultSkeletonName=skeleton.nif
 
@@ -121,6 +119,8 @@ ApplyOverallTransformToSkinAndBones=1
 bhkScaleFactor=7.0
 
 ; [Applications]
+; NiVersion - Version of Nif use by game
+; NiUserVersion - User Version of Nif used by game
 ; RootPaths - Semicolon separated list of base directories to use when determining which app the imported file is from
 ;
 ; TextureRootPaths - Semicolon separated list of base directories to look for texturefiles
@@ -132,6 +132,8 @@ bhkScaleFactor=7.0
 ; GoToSkeletonBindPosition - Morrowind trishape data is not in the correct bind position for import. Default: 1
 
 [Oblivion]
+NiVersion=20.0.0.5
+NiUserVersion=11
 ; Installation Folder
 InstallPath=[HKLM\SOFTWARE\Bethesda Softworks\Oblivion]=@"Installed Path"
 ExtractFolder=E:\Nifs\Oblivion
@@ -148,6 +150,8 @@ TextureSearchPaths=${RootPath}\Textures;${TextureRootPath}\Textures\Characters;$
 GoToSkeletonBindPosition=1
 
 [Morrowind]
+NiVersion=4.0.0.2
+NiUserVersion=0
 InstallPath=[HKLM\SOFTWARE\Bethesda Softworks\Morrowind]=@"Installed Path"
 RootPath=${InstallPath}\Data Files
 ExtractFolder=E:\Nifs\Morrowind\Data Files
@@ -157,7 +161,9 @@ TextureExtensions=.tga;
 TextureSearchPaths=${RootPath}\Textures
 GoToSkeletonBindPosition=1
 
-[Civ4]
+[Civilization 4]
+NiVersion=20.0.0.4
+NiUserVersion=0
 InstallPath=[HKEY_LOCAL_MACHINE\SOFTWARE\Firaxis Games\Sid Meier's Civilization 4]=@"INSTALLDIR"
 RootPath=
 ExtractFolder=C:\Projects\Main\Civilization4\assets
@@ -168,7 +174,9 @@ TextureSearchPaths=
 GoToSkeletonBindPosition=1
 DummyNodeMatches=MD;Bip;Bip??;* NonAccum;Effect*;Sound*;Dummy*
 
-[DAoC]
+[Dark Age of Camelot]
+NiVersion=10.1.0.0
+NiUserVersion=0
 Isles_InstallPath=[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Dark Age of Camelot - Shrouded Isles_is1]=@"InstallLocation"
 RootPath=
 ExtractFolder=
@@ -177,4 +185,8 @@ TextureRootPaths=$(ExtractFolder)
 TextureExtensions=.dds;.bmp;.tga
 TextureSearchPaths=
 GoToSkeletonBindPosition=1
-ApplyOverallTransformToSkinAndBones=0
\ No newline at end of file
+ApplyOverallTransformToSkinAndBones=0
+
+[User]
+NiVersion=20.0.0.5
+NiUserVersion=0
diff --git a/NifCommon/AppSettings.cpp b/NifCommon/AppSettings.cpp
index 59cbb30..efb8b9c 100644
--- a/NifCommon/AppSettings.cpp
+++ b/NifCommon/AppSettings.cpp
@@ -2,6 +2,7 @@
 #include <string.h>
 #include <tchar.h>
 #include "AppSettings.h"
+#include "IniSection.h"
 
 AppSettingsMap TheAppSettings;
 
@@ -18,6 +19,7 @@ void AppSettings::Initialize(Interface *gi)
 
       string Applications = GetIniValue<string>("System", "KnownApplications", "", iniName);
       stringlist apps = TokenizeString(Applications.c_str(), ";");
+      apps.push_back(string("User")); // always ensure that user is present
       for (stringlist::iterator appstr=apps.begin(); appstr != apps.end(); ++appstr){
          AppSettings* setting = FindAppSetting(*appstr);
          if (NULL == setting){
@@ -46,6 +48,9 @@ void AppSettings::ReadSettings(string iniFile)
 
    std::swap(Environment, settings);
 
+   NiVersion = GetSetting<string>("NiVersion", "20.0.0.5");
+   NiUserVersion = GetSetting<int>("NiUserVersion", 0);
+
    rootPath = GetSetting<string>("RootPath");
    rootPaths = TokenizeString(GetSetting<string>("RootPaths").c_str(), ";");
    searchPaths = TokenizeString(GetSetting<string>("TextureSearchPaths").c_str(), ";");
@@ -61,6 +66,19 @@ void AppSettings::ReadSettings(string iniFile)
    dummyNodeMatches = TokenizeString(GetSetting<string>("DummyNodeMatches").c_str(), ";");
 }
 
+void AppSettings::WriteSettings(Interface *gi)
+{
+   TCHAR iniName[MAX_PATH];
+   LPCTSTR pluginDir = gi->GetDir(APP_PLUGCFG_DIR);
+   PathCombine(iniName, pluginDir, "MaxNifTools.ini");
+   if (-1 != _taccess(iniName, 0)) 
+   {
+      SetIniValue(Name.c_str(), "NiVersion", NiVersion.c_str(), iniName);
+      SetIniValue(Name.c_str(), "NiUserVersion", FormatString("%d", NiUserVersion).c_str(), iniName);
+   }
+}
+
+
 string AppSettings::FindImage(const string& fname){
    TCHAR buffer[MAX_PATH];
 
diff --git a/NifCommon/AppSettings.h b/NifCommon/AppSettings.h
index 0d7cfec..3e009ee 100644
--- a/NifCommon/AppSettings.h
+++ b/NifCommon/AppSettings.h
@@ -42,9 +42,12 @@ public:
    NameValueCollection imgTable;
    stringlist dummyNodeMatches;
    int applyOverallTransformToSkinAndBones;
+   std::string NiVersion;
+   int NiUserVersion;
 
    static void Initialize(Interface *gi);
    void ReadSettings(std::string iniFile);
+   void WriteSettings(Interface *gi);
    std::string FindImage(const std::string& fname);
 
    // Check whether the given file is a child of the root paths
diff --git a/NifCommon/IniSection.h b/NifCommon/IniSection.h
new file mode 100644
index 0000000..e42f6a8
--- /dev/null
+++ b/NifCommon/IniSection.h
@@ -0,0 +1,124 @@
+#pragma once
+
+#include <string>
+#include <list>
+enum INIDEFTYPE
+{
+   IDT_STRING,
+   IDT_INT,
+   IDT_FLOAT,
+   IDT_BOOL,
+   IDT_FILENAME,
+   IDT_UNKNOWN,
+};
+
+struct INIDEF
+{
+   INIDEF() : ShortName(NULL), IniName(NULL), MemberAddr(0), Description(NULL), DefaultValue(NULL), ValueSize(0) {
+   }
+
+   ~INIDEF() {
+      if (ValueSize && DefaultValue) {
+         delete DefaultValue;
+         DefaultValue = NULL;
+         ValueSize = 0;
+      }
+   }
+
+   template<typename U>
+   INIDEF(LPCTSTR sName, LPCTSTR iName, const U& member, U default, LPCTSTR desc, INIDEFTYPE type) 
+      : ShortName(sName), IniName(iName), MemberAddr(NULL), Description(NULL), MemberType(type) {
+      SetDefault(default);
+   }
+
+   template<>
+   INIDEF(LPCTSTR sName, LPCTSTR iName, const std::string& member, std::string default, LPCTSTR desc, INIDEFTYPE type) 
+      : ShortName(sName), IniName(iName), MemberAddr((DWORD)&member), Description(NULL) { 
+      MemberType = type==IDT_UNKNOWN?IDT_STRING:type; 
+      SetDefault(default);
+   }
+
+   template<>
+   INIDEF(LPCTSTR sName, LPCTSTR iName, const int& member, int default, LPCTSTR desc, INIDEFTYPE type) 
+      : ShortName(sName), IniName(iName), MemberAddr((DWORD)&member), Description(NULL) { 
+      MemberType = type==IDT_UNKNOWN?IDT_INT:type; 
+      SetDefault(default);
+   }
+
+   template<>
+   INIDEF(LPCTSTR sName, LPCTSTR iName, const float& member, float default, LPCTSTR desc, INIDEFTYPE type) 
+      : ShortName(sName), IniName(iName), MemberAddr((DWORD)&member), Description(NULL) { 
+      MemberType = type==IDT_UNKNOWN?IDT_FLOAT:type; 
+      SetDefault(default);
+   }
+
+   template<>
+   INIDEF(LPCTSTR sName, LPCTSTR iName, const bool& member, bool default, LPCTSTR desc, INIDEFTYPE type) 
+      : ShortName(sName), IniName(iName), MemberAddr((DWORD)&member), Description(NULL) { 
+      MemberType = type==IDT_UNKNOWN?IDT_BOOL:type; 
+      SetDefault(default);
+   }
+
+   template<typename U>
+   void SetDefault(U default) {
+      ValueSize = sizeof(U);
+      DefaultValue = new U(default);
+   }
+
+   template <typename U>
+   const U& GetDefault() const {
+      return *(U*)DefaultValue;
+   }
+
+   LPCTSTR ShortName;
+   LPCTSTR IniName;
+   DWORD MemberAddr;
+   INIDEFTYPE MemberType;
+   LPCTSTR Description;
+   LPVOID DefaultValue;
+   DWORD ValueSize;
+};
+
+#define BEGIN_INI_MAP(name) \
+   virtual void *GetMember(const INIDEF* memptr) const { return (void*)(((char*)this) + memptr->MemberAddr); } \
+   virtual const INIDEF* GetInfDefmap() const { return InternalGetInfDefmap(); } \
+   static INIDEF* InternalGetInfDefmap() { \
+   const name* pThis = 0; \
+   static INIDEF map[] = { \
+
+#define BEGIN_INI_MAP_WITH_BASE(name, base) \
+   virtual void *GetMember(const INIDEF* memptr) const { return (void*)(((char*)this) + memptr->MemberAddr); } \
+   virtual const INIDEF* GetInfDefmap() const { return InternalGetInfDefmap(); } \
+   static INIDEF* InternalGetInfDefmap() { \
+   const name* pThis = 0; \
+   static INIDEF map[] = { \
+
+#define END_INI_MAP() \
+   INIDEF() };\
+   return map;\
+}
+
+#define ADDITEM(sName, iName, member, desc) \
+   INIDEF(sName, iName, pThis->member, desc, IDT_UNKNOWN), \
+
+#define ADDITEMEX(sName, iName, member, type, desc) \
+   INIDEF(sName, iName, pThis->member, desc, type), \
+
+struct IniFileSection
+{
+   virtual LPCTSTR GetName() const = 0;
+   virtual const INIDEF* GetInfDefmap() const = 0;
+   virtual void *GetMember(const INIDEF* memptr) const = 0;
+};
+
+typedef std::list<IniFileSection*>  IniFileSectionList;
+
+inline int GetIniDefSectionSize(IniFileSection *section) {
+   int len = 0;
+
+   for (const INIDEF *inidef = section->GetInfDefmap()
+      ; inidef != NULL && inidef->ShortName
+      ; ++inidef)
+      ++len;
+   return len;
+}
\ No newline at end of file
diff --git a/NifCommon/NifCommon_VC80.vcproj b/NifCommon/NifCommon_VC80.vcproj
index 0f75d8f..d8d7fc7 100644
--- a/NifCommon/NifCommon_VC80.vcproj
+++ b/NifCommon/NifCommon_VC80.vcproj
@@ -504,6 +504,10 @@
 				RelativePath=".\AppSettings.h"
 				>
 			</File>
+			<File
+				RelativePath=".\IniSection.h"
+				>
+			</File>
 			<File
 				RelativePath=".\NifGui.h"
 				>
@@ -516,6 +520,10 @@
 				RelativePath=".\niutils.h"
 				>
 			</File>
+			<File
+				RelativePath=".\objectParams.h"
+				>
+			</File>
 			<File
 				RelativePath=".\pch.h"
 				>
diff --git a/NifCommon/niutils.cpp b/NifCommon/niutils.cpp
index 3f2190a..f6e0b75 100644
--- a/NifCommon/niutils.cpp
+++ b/NifCommon/niutils.cpp
@@ -70,12 +70,12 @@ std::string FormatString(const TCHAR* format,...)
 }
 
 // Tokenize a string using strtok and return it as a stringlist
-stringlist TokenizeString(LPCTSTR str, LPCTSTR delims)
+stringlist TokenizeString(LPCTSTR str, LPCTSTR delims, bool trim)
 {
    stringlist values;
    LPTSTR buf = STRDUPA(str);
    for (LPTSTR p = _tcstok(buf, delims); p && *p; p = _tcstok(NULL, delims)){
-      values.push_back(string(p));
+      values.push_back(string((trim) ? Trim(p) : p));
    }
    return values;
 }
@@ -583,6 +583,22 @@ TriObject* GetTriObject(Object *o)
 }
 
 // Get or Create the Skin Modifier
+Modifier *GetOrCreateSkin(INode *node)
+{
+   Modifier *skinMod = GetSkin(node);
+   if (skinMod)
+      return skinMod;   
+   
+   IDerivedObject *dobj = CreateDerivedObject(node->GetObjectRef());
+   //create a skin modifier and add it
+   skinMod = (Modifier*) CreateInstance(OSM_CLASS_ID, SKIN_CLASSID);
+   dobj->SetAFlag(A_LOCK_TARGET);
+   dobj->AddModifier(skinMod);
+   dobj->ClearAFlag(A_LOCK_TARGET);
+   node->SetObjectRef(dobj);
+   return skinMod;
+}
+
 Modifier *GetSkin(INode *node)
 {
    Object* pObj = node->GetObjectRef();
@@ -604,14 +620,65 @@ Modifier *GetSkin(INode *node)
       }
       pObj = pDerObj->GetObjRef();
    }
+   return NULL;
+}
 
-   IDerivedObject *dobj = CreateDerivedObject(node->GetObjectRef());
 
-   //create a skin modifier and add it
-   Modifier *skinMod = (Modifier*) CreateInstance(OSM_CLASS_ID, SKIN_CLASSID);
-   dobj->SetAFlag(A_LOCK_TARGET);
-   dobj->AddModifier(skinMod);
-   dobj->ClearAFlag(A_LOCK_TARGET);
-   node->SetObjectRef(dobj);
-   return skinMod;
-}
+TSTR GetFileVersion(const char *fileName)
+{
+   TSTR retval;
+   char fileVersion[MAX_PATH];
+   if (fileName == NULL)
+   {
+      GetModuleFileName(hInstance, fileVersion, MAX_PATH);
+      fileName = fileVersion;
+   }
+   HMODULE ver = GetModuleHandle("version.dll");
+   if (!ver) ver = LoadLibrary("version.dll");
+   if (ver != NULL)
+   {
+      DWORD (APIENTRY *GetFileVersionInfoSize)(LPCTSTR, LPDWORD) = NULL;
+      BOOL (APIENTRY *GetFileVersionInfo)(LPCTSTR, DWORD, DWORD, LPVOID) = NULL;
+      BOOL (APIENTRY *VerQueryValue)(const LPVOID, LPTSTR, LPVOID *, PUINT) = NULL;
+      *(FARPROC*)&GetFileVersionInfoSize = GetProcAddress(ver, "GetFileVersionInfoSizeA");
+      *(FARPROC*)&GetFileVersionInfo = GetProcAddress(ver, "GetFileVersionInfoA");
+      *(FARPROC*)&VerQueryValue = GetProcAddress(ver, "VerQueryValueA");
+      if (GetFileVersionInfoSize && GetFileVersionInfo && VerQueryValue)
+      {
+         DWORD vLen = 0;
+         DWORD vSize = GetFileVersionInfoSize(fileName,&vLen);
+         if (vSize) 
+         {
+            LPVOID versionInfo = malloc(vSize+1);
+            if (GetFileVersionInfo(fileName,vLen,vSize,versionInfo))
+            {            
+               LPVOID version=NULL;
+               if (VerQueryValue(versionInfo,"\\VarFileInfo\\Translation",&version,(UINT *)&vLen) && vLen==4) 
+               {
+                  DWORD langD = *(DWORD*)version;
+                  sprintf(fileVersion, "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion",
+                     (langD & 0xff00)>>8,langD & 0xff,(langD & 0xff000000)>>24, (langD & 0xff0000)>>16);            
+               }
+               else 
+               {
+                  sprintf(fileVersion, "\\StringFileInfo\\%04X04B0\\ProductVersion", GetUserDefaultLangID());
+               }
+               LPCTSTR value = NULL;
+               if (VerQueryValue(versionInfo,fileVersion,&version,(UINT *)&vLen))
+                  value = LPCTSTR(version);
+               else if (VerQueryValue(versionInfo,"\\StringFileInfo\\040904B0\\ProductVersion",&version,(UINT *)&vLen))
+                  value = LPCTSTR(version);
+               if (value != NULL)
+               {
+                  stringlist val = TokenizeString(value, ",", true);
+                  if (val.size() >= 4){
+                     retval = FormatText("%s.%s.%s.%s", val[0].c_str(), val[1].c_str(), val[2].c_str(), val[3].c_str());
+                  }
+               }
+               free(versionInfo);
+            }
+         }
+      }
+   }
+   return retval;
+}
\ No newline at end of file
diff --git a/NifCommon/niutils.h b/NifCommon/niutils.h
index 1a8cf8f..11aaec2 100644
--- a/NifCommon/niutils.h
+++ b/NifCommon/niutils.h
@@ -121,7 +121,7 @@ struct NumericStringEquivalence
 // Common collections that I use
 typedef std::map<std::string, std::string, ltstr> NameValueCollection;
 typedef std::pair<std::string, std::string> KeyValuePair;
-typedef std::list<std::string> stringlist;
+typedef std::vector<std::string> stringlist;
 
 extern int wildcmp(const TCHAR *wild, const TCHAR *string);
 extern int wildcmpi(const TCHAR *wild, const TCHAR *string);
@@ -209,7 +209,7 @@ inline void SetIniValue<TSTR>(LPCTSTR Section, LPCTSTR Setting, TSTR value, LPCT
 extern TSTR FormatText(const TCHAR* format,...);
 extern std::string FormatString(const TCHAR* format,...);
 
-extern stringlist TokenizeString(LPCTSTR str, LPCTSTR delims);
+extern stringlist TokenizeString(LPCTSTR str, LPCTSTR delims, bool trim=false);
 extern string GetIndirectValue(LPCSTR path);
 extern NameValueCollection ReadIniSection(LPCTSTR Section, LPCTSTR iniFileName );
 extern string ExpandQualifiers(const string& src, const NameValueCollection& map);
@@ -271,6 +271,9 @@ static inline Color TOCOLOR(const Niflib::Color3& c3) {
    return Color(c3.r, c3.g, c3.b);
 }
 
+static inline Niflib::Color3 TOCOLOR3(const Color& c3) {
+   return Niflib::Color3(c3.r, c3.g, c3.b);
+}
 
 static inline Point3 TOPOINT3(const Niflib::Vector3& v){
    return Point3(v.x, v.y, v.z);
@@ -334,7 +337,10 @@ inline Niflib::Ref<U> SelectFirstObjectOfType( list<Niflib::Ref<T> > const & obj
 TSTR PrintMatrix3(Matrix3& m);
 TSTR PrintMatrix44(Niflib::Matrix44& m);
 
+extern Modifier *GetOrCreateSkin(INode *node);
 extern Modifier *GetSkin(INode *node);
 extern TriObject* GetTriObject(Object *o);
 
+extern TSTR GetFileVersion(const char *fileName);
+
 #endif // _NIUTILS_H_
\ No newline at end of file
diff --git a/NifCommon/objectParams.h b/NifCommon/objectParams.h
index 23a45f4..9773e3e 100644
--- a/NifCommon/objectParams.h
+++ b/NifCommon/objectParams.h
@@ -32,7 +32,7 @@ inline Value* make_maxscript_value(const Color& rgb);
 inline Value* make_maxscript_value(LPCTSTR str);
 inline Value* make_maxscript_value(ReferenceTarget* rtarg);
 
-#if VERSION_3DSMAX <= ((MAX_RELEASE_R7<<16)+(15<<8)+0)
+#if VERSION_3DSMAX <= ((7000<<16)+(15<<8)+0) // Version 7
 inline void clear_error_source_data() {}
 #endif
 
@@ -317,7 +317,8 @@ inline float ConvertMAXScriptToC<float>::cvt(Value* val)
 
 inline Color ConvertMAXScriptToC<Color>::cvt(Value* val)
 {
-	return val->to_point3();
+	Point3 pt3 = val->to_point3();
+   return Color(pt3.x/255.0f, pt3.y/255.0f, pt3.z/255.0f);
 }
 
 inline LPTSTR ConvertMAXScriptToC<LPTSTR>::cvt(Value* val)
diff --git a/NifExport/Coll.cpp b/NifExport/Coll.cpp
index 20a7ab6..5c8f30f 100755
--- a/NifExport/Coll.cpp
+++ b/NifExport/Coll.cpp
@@ -252,6 +252,9 @@ Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node)
 	// marked as collision?
 	bool coll = npIsCollision(node);
 
+   bool local = !mFlattenHierarchy;
+   NiNodeRef nodeParent = mFlattenHierarchy ? mNiRoot : parent;
+
 	NiNodeRef newParent;
 	if (coll)
 	{
@@ -275,7 +278,7 @@ Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node)
 		body->SetRotation(q);
 		body->SetTranslation(Vector3(trans.x/7, trans.y/7, trans.z/7));
 */
-		newParent = makeNode(parent, node);
+		newParent = nodeParent; // always have collision one level up?
 
 		bhkSphereRepShapeRef shape = makeCollisionShape(node);
 		bhkRigidBodyRef body = makeCollisionBody(node);
@@ -283,18 +286,17 @@ Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node)
 
 		bhkCollisionObjectRef co = DynamicCast<bhkCollisionObject>(CreateBlock("bhkCollisionObject"));
 		co->SetBody(DynamicCast<NiObject>(body));
+      
 		co->SetParent(newParent);
 
 		// link
 		newParent->SetCollisionObject(DynamicCast<NiCollisionObject>(co));
 
-	} else
-	if (isCollisionGroup(node))
-	{
-		newParent = makeNode(parent, node);
-	} else
-		newParent = parent;
-
+	} else if (isCollisionGroup(node) && !mFlattenHierarchy) {
+		newParent = makeNode(nodeParent, node);
+   } else {
+		newParent = nodeParent;
+   }
 	for (int i=0; i<node->NumberOfChildren(); i++) 
 	{
 		Result result = exportCollision(newParent, node->GetChildNode(i));
@@ -315,13 +317,13 @@ bhkRigidBodyRef Exporter::makeCollisionBody(INode *node)
 
    // Handle compatibility
    npGetProp(node, NP_HVK_MASS_OLD, mass, NP_DEFAULT_HVK_EMPTY);
-   if (mass != NP_DEFAULT_HVK_EMPTY)
+   if (mass == NP_DEFAULT_HVK_EMPTY)
       npGetProp(node, NP_HVK_MASS, mass, NP_DEFAULT_HVK_MASS);
    npGetProp(node, NP_HVK_FRICTION_OLD, frict, NP_DEFAULT_HVK_EMPTY);
-   if (frict != NP_DEFAULT_HVK_EMPTY)
+   if (frict == NP_DEFAULT_HVK_EMPTY)
       npGetProp(node, NP_HVK_FRICTION, frict, NP_DEFAULT_HVK_FRICTION);
    npGetProp(node, NP_HVK_RESTITUTION_OLD, resti, NP_DEFAULT_HVK_EMPTY);
-   if (resti != NP_DEFAULT_HVK_EMPTY)
+   if (resti == NP_DEFAULT_HVK_EMPTY)
       npGetProp(node, NP_HVK_RESTITUTION, resti, NP_DEFAULT_HVK_RESTITUTION);
 
 	npGetProp(node, NP_HVK_LAYER, lyr, NP_DEFAULT_HVK_LAYER);
@@ -336,7 +338,7 @@ bhkRigidBodyRef Exporter::makeCollisionBody(INode *node)
 	npGetProp(node, NP_HVK_CENTER, center);
 
 	// setup body
-	bhkRigidBodyRef body = DynamicCast<bhkRigidBody>(CreateBlock("bhkRigidBody"));
+	bhkRigidBodyRef body = DynamicCast<bhkRigidBody>(CreateBlock("bhkRigidBodyT"));
 
 	body->SetLayer(lyr);
 	body->SetLayerCopy(lyr);
@@ -351,6 +353,8 @@ bhkRigidBodyRef Exporter::makeCollisionBody(INode *node)
 	body->SetMaxAngularVelocity(maxangvel);
 	body->SetPenetrationDepth(pendepth);
 	body->SetCenter(center);
+   QuaternionXYZW q; q.x = q.y = q.z = 0; q.w = 1.0f;
+   body->SetRotation(q);
 
 	return body;
 }
@@ -490,7 +494,6 @@ bhkSphereRepShapeRef Exporter::makeTriStripsShape(INode *node)
 	shape->SetUnknownInts1(unknownInts1);
 */
 
-   ASSERT(!"TODO: Need to support this");
 /* Still not handled
 	vector<uint> unknownInts2;
 	unknownInts2.resize(1);
diff --git a/NifExport/Config.cpp b/NifExport/Config.cpp
index 5c4937c..f9ab730 100755
--- a/NifExport/Config.cpp
+++ b/NifExport/Config.cpp
@@ -57,6 +57,13 @@ void Exporter::writeConfig(Interface *i)
       SetIniValue(NifExportSection, "TexturePrefix", mTexPrefix, iniName);
       SetIniValue(NifExportSection, "ExportCollision", mExportCollision, iniName);
       SetIniValue(NifExportSection, "RemapIndices", mRemapIndices, iniName);
+
+      SetIniValue(NifExportSection, "ExportExtraNodes", mExportExtraNodes, iniName);
+      SetIniValue(NifExportSection, "ExportSkin", mExportSkin, iniName);
+      SetIniValue(NifExportSection, "UserPropBuffer", mUserPropBuffer, iniName);
+      SetIniValue(NifExportSection, "FlattenHierarchy", mFlattenHierarchy, iniName);
+      SetIniValue(NifExportSection, "RemoveUnreferencedBones", mRemoveUnreferencedBones, iniName);
+      SetIniValue(NifExportSection, "SortNodesToEnd", mSortNodesToEnd, iniName);
    }
 }
 
diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp
index a38bfe3..57c2e09 100755
--- a/NifExport/Exporter.cpp
+++ b/NifExport/Exporter.cpp
@@ -20,6 +20,9 @@ bool Exporter::mUserPropBuffer=false;
 bool Exporter::mFlattenHierarchy=false;
 bool Exporter::mRemoveUnreferencedBones=false;
 bool Exporter::mSortNodesToEnd=false;
+string Exporter::mGameName = "User";
+string Exporter::mNifVersion = "20.0.0.5";
+int Exporter::mNifUserVersion = 0;
 
 Exporter::Exporter(Interface *i, AppSettings *appSettings)
    : mI(i), mAppSettings(appSettings)
@@ -28,11 +31,21 @@ Exporter::Exporter(Interface *i, AppSettings *appSettings)
 
 Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node)
 {
+   //root->SetName("Scene Root");
+
 	BSXFlagsRef bsx = CreateNiObject<BSXFlags>();
 	bsx->SetName("BSX");
 	bsx->SetFlags(0x00000002);
    root->AddExtraData(DynamicCast<NiExtraData>(bsx));
-   exportUPB(root, node);
+   bool ok = exportUPB(root, node);
+
+   if (!ok && Exporter::mExportCollision)
+   {
+      NiStringExtraDataRef strings = DynamicCast<NiStringExtraData>(CreateBlock("NiStringExtraData"));	
+      strings->SetName("UPB");
+      strings->SetData("Ellasticity = 0.300000\r\nFriction = 0.300000\r\nUnyielding = 0\r\nProxy_Geometry = <None>\r\nUse_Display_Proxy = 0\r\nDisplay_Children = 1\r\nDisable_Collisions = 0\r\nInactive = 0\r\nDisplay_Proxy = <None>\r\nMass = 0.000000\r\nSimulation_Geometry = 2\r\nCollision_Groups = 589825\r\n");
+      root->AddExtraData(DynamicCast<NiExtraData>(strings));
+   }
 
 	mNiRoot = root;
 	
diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h
index a931c1b..e73a5a4 100755
--- a/NifExport/Exporter.h
+++ b/NifExport/Exporter.h
@@ -5,6 +5,7 @@ using namespace Niflib;
 
 class BitmapTex;
 class AppSettings;
+class StdMat2;
 
 class Exporter
 {
@@ -49,6 +50,9 @@ public:
    static bool          mFlattenHierarchy;
    static bool          mRemoveUnreferencedBones;
    static bool          mSortNodesToEnd;
+   static string        mGameName;
+   static string        mNifVersion;
+   static int           mNifUserVersion;
 
 	Exporter(Interface *i, AppSettings *appSettings);
 
@@ -108,7 +112,8 @@ private:
 	void					nodeTransform(QuaternionXYZW &rot, Vector3 &trans, INode *node, TimeValue t, bool local=true);
 	Point3					getVertexNormal(Mesh* mesh, int faceNo, RVertex* rv);
 	bool					equal(const Vector3 &a, const Point3 &b, float thresh);
-	BitmapTex				*getTexture(Mtl *mtl);
+   BitmapTex				*getTexture(Mtl *mtl);
+   BitmapTex				*getTexture(Mtl *mtl, int i);
 	void					getTextureMatrix(Matrix3 &mat, Mtl *mtl);
    NiNodeRef				makeNode(NiNodeRef &parent, INode *maxNode, bool local=true);
    NiNodeRef				getNode(const string& name);
@@ -138,8 +143,10 @@ private:
 	/* texture & material */
 	// creates NiTexturingProperty + NiSourceTexture
 	void					makeTexture(NiAVObjectRef &parent, Mtl *mtl);
+   bool              makeTextureDesc(BitmapTex *bmTex, Niflib::TexDesc &td);
 	// creates a NiMaterialProperty
 	void					makeMaterial(NiAVObjectRef &parent, Mtl *mtl);
+   bool              exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl);
 
 	/* havok & collision */
 	int						addVertex(vector<Vector3> &verts, vector<Vector3> &vnorms, const Point3 &pt, const Point3 &norm);
diff --git a/NifExport/Mesh.cpp b/NifExport/Mesh.cpp
index 2ec3cb8..8c29ba4 100755
--- a/NifExport/Mesh.cpp
+++ b/NifExport/Mesh.cpp
@@ -251,7 +251,6 @@ NiTriBasedGeomRef Exporter::makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp
 
 	NiAVObjectRef av(DynamicCast<NiAVObject>(shape));
 	makeMaterial(av, mtl);
-	makeTexture(av, mtl);
 
 	parent->AddChild(DynamicCast<NiAVObject>(shape));
 
@@ -265,8 +264,10 @@ int Exporter::addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matr
 	Point3 norm = getVertexNormal(mesh, face, mesh->getRVertPtr(vidx));
 
 	Point3 uv;
-	if (mesh->tVerts && mesh->tvFace)
+   if (mesh->tVerts && mesh->tvFace) {
 		uv = mesh->tVerts[ mesh->tvFace[ face ].t[ vi ]] * texm;
+      uv.y += 1.0f;
+   }
 
    Color4 col(1.0f, 1.0f, 1.0f);
    if (mVertexColors && !vertColors.empty()){
@@ -282,7 +283,7 @@ int Exporter::addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matr
 		if (equal(grp.verts[i], pt, mWeldThresh) &&
 			equal(grp.vnorms[i], norm, 0))
 		{
-			if (mesh->tvFace && (grp.uvs[i].u!=uv.x || grp.uvs[i].v!=uv.y))
+			if (mesh->tVerts && mesh->tvFace && (grp.uvs[i].u!=uv.x || grp.uvs[i].v!=uv.y))
 				continue;
 
 			if (mVertexColors && !vertColors.empty() &&
diff --git a/NifExport/MtlTex.cpp b/NifExport/MtlTex.cpp
index a18a2b2..75b4089 100755
--- a/NifExport/MtlTex.cpp
+++ b/NifExport/MtlTex.cpp
@@ -1,20 +1,76 @@
 #include "pch.h"
 #include "stdmat.h"
+#include "shaders.h"
 #include "AppSettings.h"
+#include "obj/NiWireframeProperty.h"
+#include "obj/NiAlphaProperty.h"
+#include "obj/NiStencilProperty.h"
+#include "obj/NiShadeProperty.h"
+#include "obj/NiVertexColorProperty.h"
+#include "obj/NiDitherProperty.h"
+#include "obj/NiSpecularProperty.h"
 
 void Exporter::makeTexture(NiAVObjectRef &parent, Mtl *mtl)
 {
-	BitmapTex *bmTex = getTexture(mtl);
-
+   BitmapTex *bmTex = getTexture(mtl);
 	if (!bmTex)
-		return;
+      return;
 
-	NiTexturingPropertyRef texProp(DynamicCast<NiTexturingProperty>(CreateBlock("NiTexturingProperty")));
+	NiTexturingPropertyRef texProp = CreateNiObject<NiTexturingProperty>();
 	texProp->SetApplyMode(APPLY_MODULATE);
 	texProp->SetTextureCount(7);
 
 	TexDesc td;
-	td.source = DynamicCast<NiSourceTexture>(CreateBlock("NiSourceTexture"));
+   if (makeTextureDesc(bmTex, td))
+	   texProp->SetTexture(BASE_MAP, td);
+
+	NiPropertyRef prop = DynamicCast<NiProperty>(texProp);
+	parent->AddProperty(prop);
+}
+
+bool Exporter::makeTextureDesc(BitmapTex *bmTex, TexDesc& td)
+{
+   td.source = CreateNiObject<NiSourceTexture>();
+
+   // Filtering
+   switch (bmTex->GetFilterType())
+   {
+   case FILTER_PYR:  td.filterMode = FILTER_TRILERP; break;
+   case FILTER_SAT:  td.filterMode = FILTER_BILERP; break;
+   case FILTER_NADA: td.filterMode = FILTER_NEAREST; break;
+   }
+
+   td.clampMode = TexClampMode();  
+   switch (bmTex->GetTextureTiling())
+   {
+   case 3: td.clampMode = WRAP_S_WRAP_T; break;
+   case 1: td.clampMode = WRAP_S_CLAMP_T; break;
+   case 2: td.clampMode = CLAMP_S_WRAP_T; break;
+   case 0: td.clampMode = CLAMP_S_CLAMP_T; break;
+   }
+
+   if (UVGen *uvGen = bmTex->GetTheUVGen()){
+      if (RefTargetHandle ref = uvGen->GetReference(0)){
+         TexCoord trans, tiling;
+         float wangle;
+         bool ok = true;
+         if(ok) ok &= getMAXScriptValue(ref, "U_Offset", 0, trans.u);
+         if(ok) ok &= getMAXScriptValue(ref, "V_Offset", 0, trans.v);
+         if(ok) ok &= getMAXScriptValue(ref, "U_Tiling", 0, tiling.u);
+         if(ok) ok &= getMAXScriptValue(ref, "V_Tiling", 0, tiling.v);
+         if(ok) ok &= getMAXScriptValue(ref, "W_Angle", 0, wangle);
+         if (ok) {
+            if (trans.u != 0.0f || trans.v != 0.0f || tiling.u != 1.0f || tiling.v != 1.0f || wangle != 0.0f) {
+               td.hasTextureTransform = true;
+               td.translation = trans;
+               td.tiling = tiling;
+               td.wRotation = TORAD(wangle);
+               td.transformType_ = 1;
+               td.centerOffset = TexCoord(0.5, 0.5);
+            }
+         }
+      }
+   }
 
    // Get file name and check if it matches the "app" settings in the ini file
    TSTR mapPath;
@@ -31,23 +87,25 @@ void Exporter::makeTexture(NiAVObjectRef &parent, Mtl *mtl)
    {
       TSTR p, f;
       SplitPathFile(mapPath, &p, &f);
-	   TSTR newPath;
-	   if (mTexPrefix != "")
-		   newPath = TSTR(mTexPrefix.c_str()) + _T("\\") + f;
-	   else
-		   newPath = f;
-   	
+      TSTR newPath;
+      if (mTexPrefix != "")
+         newPath = TSTR(mTexPrefix.c_str()) + _T("\\") + f;
+      else
+         newPath = f;
+
       NiObjectRef unk_link(NULL);
-	   td.source->SetExternalTexture(newPath.data(), unk_link);
+      td.source->SetExternalTexture(newPath.data(), unk_link);
    }
-	texProp->SetTexture(BASE_MAP, td);
-
-	NiPropertyRef prop = DynamicCast<NiProperty>(texProp);
-	parent->AddProperty(prop);
+   return true;
 }
 
 void Exporter::makeMaterial(NiAVObjectRef &parent, Mtl *mtl)
 {
+   // Fill-in using the Civ4 Shader if available
+   bool done = exportCiv4Shader(parent, mtl);
+   if (done)
+      return;
+
 	string name;
 	NiMaterialPropertyRef mtlProp(DynamicCast<NiMaterialProperty>(CreateBlock("NiMaterialProperty")));
 	if (mtl)
@@ -74,6 +132,29 @@ void Exporter::makeMaterial(NiAVObjectRef &parent, Mtl *mtl)
       {
          StdMat2 * smtl = (StdMat2*)mtl;
          mtlProp->SetTransparency(smtl->GetOpacity(0));
+
+         if (smtl->SupportsShaders()) {
+            if (Shader *s = smtl->GetShader()) {
+               if (smtl->GetWire()){
+                  NiWireframePropertyRef wireProp = CreateNiObject<NiWireframeProperty>();
+                  wireProp->SetFlags(1);
+                  parent->AddProperty(wireProp);
+               }
+               if (smtl->GetTwoSided()){
+                  NiStencilPropertyRef stencil = CreateNiObject<NiStencilProperty>();
+                  stencil->SetStencilFunction(4);
+                  stencil->SetStencilEnabled(false);
+                  stencil->SetPassAction(3);
+                  stencil->SetDrawMode(3);
+                  parent->AddProperty(stencil);
+               }
+               if (smtl->IsFaceted()) {
+                  NiShadePropertyRef shade = CreateNiObject<NiShadeProperty>();
+                  shade->SetFlags(0);
+                  parent->AddProperty(shade);
+               }
+            }
+         }
       }
 	} else
 	{
@@ -90,6 +171,8 @@ void Exporter::makeMaterial(NiAVObjectRef &parent, Mtl *mtl)
 
 	NiPropertyRef prop = DynamicCast<NiProperty>(mtlProp);
 	parent->AddProperty(prop);
+
+   makeTexture(parent, mtl);
 }
 
 
@@ -133,6 +216,21 @@ BitmapTex *Exporter::getTexture(Mtl *mtl)
 	return bmTex;
 }
 
+BitmapTex *Exporter::getTexture(Mtl *mtl, int i)
+{
+   if (mtl) {
+      int texMaps = mtl->NumSubTexmaps();
+      if (i < texMaps) {
+         if (Texmap *texMap = mtl->GetSubTexmap(i)) {
+            if (texMap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) {
+               return (BitmapTex*)texMap;
+            }
+         }
+      }
+   }
+   return NULL;
+}
+
 void Exporter::getTextureMatrix(Matrix3 &mat, Mtl *mtl)
 {
 	BitmapTex *tex = getTexture(mtl);
@@ -141,3 +239,207 @@ void Exporter::getTextureMatrix(Matrix3 &mat, Mtl *mtl)
 	else
 		mat.IdentityMatrix();
 }
+
+
+bool Exporter::exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl)
+{
+   if (!mtl) 
+      return false;
+
+   RefTargetHandle ref = mtl->GetReference(2/*shader*/);
+   if (!ref)
+      return false;
+
+   TSTR shaderByName;
+   if(mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0) )
+   {
+      StdMat2 * smtl = (StdMat2*)mtl;
+      if (smtl->SupportsShaders()) {
+         if (Shader *s = smtl->GetShader()) {
+            s->GetClassName(shaderByName);
+         }
+      }
+   }
+   if (shaderByName != TSTR("CivilizationIV Shader"))
+         return false;
+
+   //if (Shader *s = mtl->GetShader()) {
+   //   TSTR className;
+   //   s->GetClassName(className);
+   //   if (className != TSTR("CivilizationIV Shader"))
+   //      return false;
+
+   Color ambient = Color(0.0f,0.0f,0.0f), diffuse = Color(0.0f,0.0f,0.0f), specular = Color(0.0f,0.0f,0.0f), emittance = Color(0.0f,0.0f,0.0f);
+   float shininess = 0.0f, alpha = 0.0f, Magnitude = 0.0f, LumaScale = 0.0f, LumaOffset = 0.0f;
+   int TestRef = 0, srcBlend = 0, destBlend = 0, TestMode = 0;
+   bool AlphaTestEnable = false;
+   int ApplyMode = 0, SrcVertexMode = 0, LightingMode = 0;
+   bool VertexColorsEnable = false, SpecularEnable = false, NoSorter = false, Dither = false;
+   int alphaMode = 0, BaseTextureExport=0, DarkTextureExport=0, DetailTextureExport=0;
+   int Decal1TextureExport=0, Decal2TextureExport=0, GlossTextureExport=0, GlowTextureExport=0;
+   LPTSTR CustomShader = NULL;
+   int ShaderViewerTechnique=0, ShaderExportTechnique=0;
+   bool UseNormalMaps = false;
+   int NormalMapTechnique=0;
+
+   bool ok = true;
+   
+   if(ok) ok &= getMAXScriptValue(ref, "ambient", 0, ambient );
+   if(ok) ok &= getMAXScriptValue(ref, "diffuse", 0, diffuse );
+   if(ok) ok &= getMAXScriptValue(ref, "specular", 0, specular );
+   if(ok) ok &= getMAXScriptValue(ref, "emittance", 0, emittance );
+   if(ok) ok &= getMAXScriptValue(ref, "shininess", 0, shininess );
+   if(ok) ok &= getMAXScriptValue(ref, "alpha", 0, alpha );
+   if(ok) ok &= getMAXScriptValue(ref, "Bump_Map_Magnitude", 0, Magnitude);
+   if(ok) ok &= getMAXScriptValue(ref, "Bump_Map_Luma_Scale", 0, LumaScale);
+   if(ok) ok &= getMAXScriptValue(ref, "Bump_Map_Luma_offset", 0, LumaOffset);
+   if(ok) ok &= getMAXScriptValue(ref, "TestRef", 0, TestRef );
+   if(ok) ok &= getMAXScriptValue(ref, "AlphaTestEnable", 0, AlphaTestEnable );
+   if(ok) ok &= getMAXScriptValue(ref, "Vertex_Color_Enable", 0, VertexColorsEnable);
+   if(ok) ok &= getMAXScriptValue(ref, "SpecularEnable", 0, SpecularEnable);
+   if(ok) ok &= getMAXScriptValue(ref, "NoSorter", 0, NoSorter);
+   if(ok) ok &= getMAXScriptValue(ref, "Dither", 0, Dither );
+   if(ok) ok &= getMAXScriptValue(ref, "UseNormalMaps", 0, UseNormalMaps );
+   if(ok) ok &= getMAXScriptValue(ref, "srcBlend", 0, srcBlend);
+   if(ok) ok &= getMAXScriptValue(ref, "destBlend", 0, destBlend);
+   if(ok) ok &= getMAXScriptValue(ref, "TestMode", 0, TestMode );
+   if(ok) ok &= getMAXScriptValue(ref, "ApplyMode", 0, ApplyMode);
+   if(ok) ok &= getMAXScriptValue(ref, "SourceVertexMode", 0, SrcVertexMode);
+   if(ok) ok &= getMAXScriptValue(ref, "LightingMode", 0, LightingMode);
+   if(ok) ok &= getMAXScriptValue(ref, "alphaMode", 0, alphaMode);
+   if(ok) ok &= getMAXScriptValue(ref, "BaseTextureExport", 0, BaseTextureExport);
+   if(ok) ok &= getMAXScriptValue(ref, "DarkTextureExport", 0, DarkTextureExport);
+   if(ok) ok &= getMAXScriptValue(ref, "DetailTextureExport", 0, DetailTextureExport);
+   if(ok) ok &= getMAXScriptValue(ref, "Decal1TextureExport", 0, Decal1TextureExport);
+   if(ok) ok &= getMAXScriptValue(ref, "Decal2TextureExport", 0, Decal2TextureExport);
+   if(ok) ok &= getMAXScriptValue(ref, "GlossTextureExport", 0, GlossTextureExport);
+   if(ok) ok &= getMAXScriptValue(ref, "GlowTextureExport", 0, GlowTextureExport);
+   if(ok) ok &= getMAXScriptValue(ref, "CustomShader", 0, CustomShader );
+   if(ok) ok &= getMAXScriptValue(ref, "ShaderViewerTechnique", 0, ShaderViewerTechnique);
+   if(ok) ok &= getMAXScriptValue(ref, "ShaderExportTechnique", 0, ShaderExportTechnique);
+   if(ok) ok &= getMAXScriptValue(ref, "NormalMapTechnique", 0, NormalMapTechnique );
+   
+   if (ok) // civ4 shader
+   {
+      NiMaterialPropertyRef mtlProp = CreateNiObject<NiMaterialProperty>();
+      parent->AddProperty(mtlProp);
+
+      mtlProp->SetName((char*)mtl->GetName());
+      mtlProp->SetAmbientColor(TOCOLOR3(ambient));
+      mtlProp->SetDiffuseColor(TOCOLOR3(diffuse));
+      mtlProp->SetSpecularColor(TOCOLOR3(specular));
+      mtlProp->SetEmissiveColor(TOCOLOR3(emittance));
+      mtlProp->SetGlossiness(shininess);
+      mtlProp->SetTransparency(alpha/100.0f);
+      if(mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0) )
+      {
+         StdMat2 * smtl = (StdMat2*)mtl;
+         if (smtl->SupportsShaders()) {
+            if (Shader *s = smtl->GetShader()) {
+               if (smtl->GetWire()){
+                  NiWireframePropertyRef wireProp = CreateNiObject<NiWireframeProperty>();
+                  wireProp->SetFlags(1);
+                  parent->AddProperty(wireProp);
+               }
+               if (smtl->GetTwoSided()){
+                  NiStencilPropertyRef stencil = CreateNiObject<NiStencilProperty>();
+                  stencil->SetStencilFunction(4);
+                  stencil->SetStencilEnabled(false);
+                  stencil->SetPassAction(3);
+                  stencil->SetDrawMode(3);
+                  parent->AddProperty(stencil);
+               }
+               if (smtl->IsFaceted()) {
+                  NiShadePropertyRef shade = CreateNiObject<NiShadeProperty>();
+                  shade->SetFlags(0);
+                  parent->AddProperty(shade);
+               }
+            }
+         }
+      }
+      if (VertexColorsEnable && (SrcVertexMode != 2 || LightingMode != 1)) {
+         NiVertexColorPropertyRef vertexColor = CreateNiObject<NiVertexColorProperty>();
+         parent->AddProperty(vertexColor);
+         vertexColor->SetVertexMode(VertMode(SrcVertexMode));
+         vertexColor->SetLightingMode(LightMode(LightingMode));
+         vertexColor->SetFlags(LightingMode + (SrcVertexMode << 3));
+      }
+      if (SpecularEnable) {
+         NiSpecularPropertyRef prop = CreateNiObject<NiSpecularProperty>();
+         parent->AddProperty(prop);
+         prop->SetFlags(1);
+
+      }
+      if (Dither) {
+         NiDitherPropertyRef prop = CreateNiObject<NiDitherProperty>();
+         parent->AddProperty(prop);
+         prop->SetFlags(1);
+      }
+      if (alphaMode != 0 || AlphaTestEnable) {
+         // always add alpha ???
+         NiAlphaPropertyRef alphaProp = CreateNiObject<NiAlphaProperty>();
+         parent->AddProperty(alphaProp);
+         alphaProp->SetAlphaBlend(true);
+         if (alphaMode == 0) { // automatic
+            alphaProp->SetSourceBlendMode(NiAlphaProperty::BlendMode(srcBlend));
+            alphaProp->SetDestBlendMode(NiAlphaProperty::BlendMode(destBlend));
+         } else if (alphaMode == 1) { // None
+            alphaProp->SetAlphaBlend(false);
+            alphaProp->SetSourceBlendMode(NiAlphaProperty::BM_SRC_ALPHA);
+            alphaProp->SetDestBlendMode(NiAlphaProperty::BM_ONE_MINUS_SRC_ALPHA);
+         } else if (alphaMode == 2) { // Standard
+            alphaProp->SetSourceBlendMode(NiAlphaProperty::BM_SRC_ALPHA);
+            alphaProp->SetDestBlendMode(NiAlphaProperty::BM_ONE_MINUS_SRC_ALPHA);
+         } else if (alphaMode == 3) { // Additive
+            alphaProp->SetSourceBlendMode(NiAlphaProperty::BM_ONE);
+            alphaProp->SetDestBlendMode(NiAlphaProperty::BM_ONE);
+         } else if (alphaMode == 4) { // Multiplicative
+            alphaProp->SetSourceBlendMode(NiAlphaProperty::BM_ZERO);
+            alphaProp->SetDestBlendMode(NiAlphaProperty::BM_SRC_COLOR);
+         } else { // Advanced
+            alphaProp->SetSourceBlendMode(NiAlphaProperty::BlendMode(srcBlend));
+            alphaProp->SetDestBlendMode(NiAlphaProperty::BlendMode(destBlend));
+         }
+         alphaProp->SetTestMode(NiAlphaProperty::TestMode(TestMode));
+         alphaProp->SetAlphaSort(!NoSorter);
+         alphaProp->SetAlphaTestThreshold(TestRef);
+         alphaProp->SetAlphaTest(AlphaTestEnable);
+      }
+
+      int ntex = mtl->NumSubTexmaps();
+      if (ntex > 0)
+      {
+         ntex = min(ntex, 7);
+         TexType texmap[] = {BASE_MAP, DARK_MAP, DETAIL_MAP, DECAL_0_MAP, BUMP_MAP, GLOSS_MAP, GLOW_MAP, DECAL_1_MAP};
+         NiTexturingPropertyRef texProp = CreateNiObject<NiTexturingProperty>();       
+         texProp->SetApplyMode(Niflib::ApplyMode(ApplyMode));
+         texProp->SetTextureCount(7);
+         for (int i = 0; i < ntex; ++i) {
+
+            BitmapTex *bmTex = getTexture(mtl, i);
+            if (!bmTex)
+               continue;
+
+            TexDesc td;
+            if (makeTextureDesc(bmTex, td)) {
+               TexType textype = texmap[i];
+               texProp->SetTexture(textype, td);
+               if (textype == BUMP_MAP) {
+                  td.source->SetPixelLayout(PIX_LAY_BUMPMAP);
+                  texProp->SetLumaOffset(LumaOffset);
+                  texProp->SetLumaScale(LumaScale);
+
+                  Matrix22 m2;
+                  m2[0][0] = m2[1][1] = Magnitude;
+                  m2[0][1] = m2[1][0] = 0.0f;
+                  texProp->SetBumpMapMatrix(m2);
+               }
+            }
+         }
+
+         parent->AddProperty(texProp);
+      }
+      return true;
+   }
+   return false;
+}
diff --git a/NifExport/NifExport.cpp b/NifExport/NifExport.cpp
index 4095a3a..2605160 100755
--- a/NifExport/NifExport.cpp
+++ b/NifExport/NifExport.cpp
@@ -66,6 +66,16 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA
 	{
 		case WM_INITDIALOG:
 			{
+            // Append file version to dialog
+            TSTR fileVersion = GetFileVersion(NULL);
+            if (!fileVersion.isNull()) {
+               char buffer[256];
+               GetWindowText(hWnd, buffer, _countof(buffer));
+               _tcscat(buffer, TEXT(" "));
+               _tcscat(buffer, fileVersion);
+               SetWindowText(hWnd, buffer);
+            }
+
 				imp = (NifExport *)lParam;
 				CenterWindow(hWnd,GetParent(hWnd));
 				CheckDlgButton(hWnd, IDC_CHK_STRIPS, Exporter::mTriStrips);
@@ -75,7 +85,23 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA
 				CheckDlgButton(hWnd, IDC_CHK_VCOLORS, Exporter::mVertexColors);
 				SetDlgItemText(hWnd, IDC_ED_TEXPREFIX, Exporter::mTexPrefix.c_str());
 				CheckDlgButton(hWnd, IDC_CHK_COLL, Exporter::mExportCollision);
-				CheckDlgButton(hWnd, IDC_CHK_REMAP, Exporter::mRemapIndices);
+            CheckDlgButton(hWnd, IDC_CHK_REMAP, Exporter::mRemapIndices);
+
+            CheckDlgButton(hWnd, IDC_CHK_EXTRA, Exporter::mExportExtraNodes);
+            CheckDlgButton(hWnd, IDC_CHK_SKIN, Exporter::mExportSkin);
+            CheckDlgButton(hWnd, IDC_CHK_UPB, Exporter::mUserPropBuffer);
+            CheckDlgButton(hWnd, IDC_CHK_HIER, Exporter::mFlattenHierarchy);
+            CheckDlgButton(hWnd, IDC_CHK_REM_BONES, Exporter::mRemoveUnreferencedBones);
+            CheckDlgButton(hWnd, IDC_CHK_SORTNODES, Exporter::mSortNodesToEnd);
+
+            string selection = Exporter::mGameName;
+            string version = Exporter::mNifVersion;
+            string userVer = FormatString("%d", Exporter::mNifUserVersion);
+            for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr)
+               SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_ADDSTRING, 0, LPARAM(itr->Name.c_str()));
+            SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_SELECTSTRING, WPARAM(-1), LPARAM(selection.c_str()));
+            SendDlgItemMessage(hWnd, IDC_CB_VERSION, WM_SETTEXT, 0, LPARAM(version.c_str()));
+            SendDlgItemMessage(hWnd, IDC_CB_USER_VERSION, WM_SETTEXT, 0, LPARAM(userVer.c_str()));
 
 				TSTR tmp;
 				tmp.printf("%.4f", Exporter::mWeldThresh);
@@ -92,11 +118,23 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA
 		case WM_COMMAND:
 			if (HIWORD(wParam) == BN_CLICKED)
 			{
-				char tmp[MAX_PATH];
+				char tmp[MAX_PATH], *end;
 				bool close = false;
 				switch (LOWORD(wParam))
 				{
 					case IDOK:
+                  // Validity Check
+                  GetDlgItemText(hWnd, IDC_CB_VERSION, tmp, MAX_PATH);
+                  if (tmp[0] != 0)
+                  {
+                     int nifVersion = GetVersion(tmp);
+                     if (!IsVersionSupported(nifVersion))
+                     {
+                        MessageBox(hWnd, FormatString("Version '%s' is not a supported version.", tmp).c_str(), "NifExport", MB_OK|MB_ICONSTOP);
+                        return FALSE;
+                     }
+                  }
+
 						Exporter::mTriStrips = IsDlgButtonChecked(hWnd, IDC_CHK_STRIPS);
 						Exporter::mExportHidden = IsDlgButtonChecked(hWnd, IDC_CHK_HIDDEN);
 						Exporter::mExportFurn = IsDlgButtonChecked(hWnd, IDC_CHK_FURN);
@@ -104,6 +142,13 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA
 						Exporter::mVertexColors = IsDlgButtonChecked(hWnd, IDC_CHK_VCOLORS);
 						Exporter::mExportCollision = IsDlgButtonChecked(hWnd, IDC_CHK_COLL);
 						Exporter::mRemapIndices = IsDlgButtonChecked(hWnd, IDC_CHK_REMAP);
+
+                  Exporter::mExportExtraNodes = IsDlgButtonChecked(hWnd, IDC_CHK_EXTRA);
+                  Exporter::mExportSkin = IsDlgButtonChecked(hWnd, IDC_CHK_SKIN);
+                  Exporter::mUserPropBuffer = IsDlgButtonChecked(hWnd, IDC_CHK_UPB);
+                  Exporter::mFlattenHierarchy = IsDlgButtonChecked(hWnd, IDC_CHK_HIER);
+                  Exporter::mRemoveUnreferencedBones = IsDlgButtonChecked(hWnd, IDC_CHK_REM_BONES);
+                  Exporter::mSortNodesToEnd = IsDlgButtonChecked(hWnd, IDC_CHK_SORTNODES);
 							
 						GetDlgItemText(hWnd, IDC_ED_TEXPREFIX, tmp, MAX_PATH);
 						Exporter::mTexPrefix = tmp;
@@ -111,6 +156,16 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA
 						GetDlgItemText(hWnd, IDC_ED_WELDTHRESH, tmp, MAX_PATH);
 						Exporter::mWeldThresh = atof(tmp);
 
+                  GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH);
+                  if (AppSettings *appSettings = FindAppSetting(tmp))
+                  {
+                     Exporter::mGameName = appSettings->Name;
+                     GetDlgItemText(hWnd, IDC_CB_VERSION, tmp, MAX_PATH);
+                     Exporter::mNifVersion = tmp;
+                     GetDlgItemText(hWnd, IDC_CB_USER_VERSION, tmp, MAX_PATH);
+                     Exporter::mNifUserVersion = strtol(tmp, &end, 0);
+                  }
+
 						EndDialog(hWnd, imp->mDlgResult=IDOK);
 						close = true;
 						break;
@@ -124,8 +179,7 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA
 				if (close)
 					SendMessage(hWnd, WM_CLOSE, 0, 0);
 			}
-
-			if (HIWORD(wParam) == STN_CLICKED)
+         else if (HIWORD(wParam) == STN_CLICKED)
 			{
 				if (LOWORD(wParam) == IDC_LBL_LINK)
 				{
@@ -133,7 +187,21 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA
 						         NULL, NULL, SW_SHOWDEFAULT);
 				}
 			}
-
+         else if (HIWORD(wParam) == CBN_SELCHANGE)
+         {
+            if (LOWORD(wParam) == IDC_CB_GAME)
+            {
+               char tmp[MAX_PATH];
+               GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH);
+               if (AppSettings *appSettings = FindAppSetting(tmp))
+               {
+                  string version = appSettings->NiVersion;
+                  string userVer = FormatString("%d", appSettings->NiUserVersion);
+                  SendDlgItemMessage(hWnd, IDC_CB_VERSION, WM_SETTEXT, 0, LPARAM(version.c_str()));
+                  SendDlgItemMessage(hWnd, IDC_CB_USER_VERSION, WM_SETTEXT, 0, LPARAM(userVer.c_str()));
+               }
+            }
+         }
 			break;
 	}
 	return FALSE;
@@ -243,12 +311,15 @@ int	NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL
          appSettings = FindAppSetting(curapp);
       }
    }
-   if (appSettings == NULL && !TheAppSettings.empty()){
+   if (appSettings == NULL && !TheAppSettings.empty())
       appSettings = &TheAppSettings.front();
-   }
 
 	if(!suppressPrompts)
 	{
+      Exporter::mGameName = appSettings->Name;
+      Exporter::mNifVersion = appSettings->NiVersion;
+      Exporter::mNifUserVersion = appSettings->NiUserVersion;
+
 		if (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), NifExportOptionsDlgProc, (LPARAM)this) != IDOK)
 			return true;
 
@@ -256,10 +327,28 @@ int	NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL
 		Exporter::writeConfig(i);
 		// write config to root node
 		Exporter::writeConfig(i->GetRootNode());
+
+      // Update the current app version
+      appSettings = FindAppSetting(Exporter::mGameName);
+      if (appSettings == NULL && !TheAppSettings.empty())
+         appSettings = &TheAppSettings.front();
+      appSettings->NiVersion = Exporter::mNifVersion;
+      appSettings->NiUserVersion = Exporter::mNifUserVersion;
+      appSettings->WriteSettings(i);
 	}
 
 	try
 	{
+      int nifVersion = VER_20_0_0_5;
+      int nifUserVer = Exporter::mNifUserVersion;
+
+      if (!Exporter::mNifVersion.empty())
+      {
+         nifVersion = GetVersion(Exporter::mNifVersion);
+         if (!IsVersionSupported(nifVersion))
+            throw exception(FormatString("Version '%s' is not a supported version.").c_str());
+      }
+
 		Exporter::mSelectedOnly = (options&SCENE_EXPORT_SELECTED) != 0;
 		Exporter exp(i, appSettings);
 		
@@ -269,7 +358,7 @@ int	NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL
 		if (result!=Exporter::Ok)
 			throw exception("Unknown error.");
 
-		WriteNifTree(name, NiObjectRef(root), VER_20_0_0_5, 11);
+		WriteNifTree(name, NiObjectRef(root), nifVersion, nifUserVer);
 	}
 
 	catch (exception &e)
diff --git a/NifExport/NifExport.rc b/NifExport/NifExport.rc
index 0386678..efbb97a 100755
--- a/NifExport/NifExport.rc
+++ b/NifExport/NifExport.rc
@@ -13,7 +13,7 @@
 #undef APSTUDIO_READONLY_SYMBOLS
 
 /////////////////////////////////////////////////////////////////////////////
-// Deutsch (Deutschland) resources
+// German (Germany) resources
 
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
 #ifdef _WIN32
@@ -35,12 +35,12 @@ END
 
 #endif    // APSTUDIO_INVOKED
 
-#endif    // Deutsch (Deutschland) resources
+#endif    // German (Germany) resources
 /////////////////////////////////////////////////////////////////////////////
 
 
 /////////////////////////////////////////////////////////////////////////////
-// Englisch (USA) resources
+// English (U.S.) resources
 
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
 #ifdef _WIN32
@@ -73,48 +73,43 @@ END
 // Dialog
 //
 
-IDD_PANEL DIALOGEX 0, 0, 200, 137
-STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | 
-    WS_SYSMENU
+IDD_PANEL DIALOGEX 0, 0, 207, 187
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 EXSTYLE WS_EX_TOOLWINDOW
 CAPTION "Export Nif"
 FONT 8, "MS Sans Serif", 0, 0, 0x1
 BEGIN
-    CONTROL         "",IDC_EDIT,"CustEdit",NOT WS_VISIBLE | WS_TABSTOP,148,8,
-                    35,10
-    CONTROL         "",IDC_SPIN,"SpinnerControl",NOT WS_VISIBLE,186,7,7,10
-    PUSHBUTTON      "&Export",IDOK,5,115,34,14
-    PUSHBUTTON      "&Cancel",IDCANCEL,45,115,33,14
-    CONTROL         "Include &Hidden",IDC_CHK_HIDDEN,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,80,5,64,10
-    CONTROL         "Generate &Strips",IDC_CHK_STRIPS,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,5,5,65,10
-    CONTROL         "Furniture &Markers",IDC_CHK_FURN,"Button",
-                    BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,5,15,71,10
-    EDITTEXT        IDC_ED_TEXPREFIX,5,60,190,12,ES_AUTOHSCROLL
-    LTEXT           "Texture &Prefix",IDC_STATIC,5,50,44,8
-    CONTROL         "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | 
-                    WS_DISABLED | WS_TABSTOP,5,25,35,10
-    EDITTEXT        IDC_ED_WELDTHRESH,163,22,35,12,ES_AUTOHSCROLL | NOT 
-                    WS_VISIBLE | WS_DISABLED
-    LTEXT           "Auto-&Weld",IDC_LBL_WELDTHRESH,160,30,34,8,NOT 
-                    WS_VISIBLE | WS_DISABLED
-    CONTROL         "Export Co&llision",IDC_CHK_COLL,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,80,15,68,10
-    CONTROL         "&Vertex Colors",IDC_CHK_VCOLORS,"Button",
-                    BS_AUTOCHECKBOX | WS_TABSTOP,80,25,68,10
-    LTEXT           "http://niftools.sourceforge.net",IDC_LBL_LINK,98,114,95,
-                    14,SS_NOTIFY | SS_CENTERIMAGE
-    CONTROL         "&Remap Indices",IDC_CHK_REMAP,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,80,35,68,10
-    COMBOBOX        IDC_CB_GAME,5,90,105,70,CBS_DROPDOWN | CBS_SORT | 
-                    WS_DISABLED | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "Game",IDC_STATIC,5,79,66,8,WS_DISABLED
-    EDITTEXT        IDC_CB_VERSION,115,90,45,12,ES_AUTOHSCROLL | WS_DISABLED
-    LTEXT           "Version",IDC_STATIC,115,79,39,8,WS_DISABLED
-    EDITTEXT        IDC_CB_USER_VERSION,165,90,30,12,ES_AUTOHSCROLL | 
-                    WS_DISABLED
-    LTEXT           "User",IDC_STATIC,165,79,25,8,WS_DISABLED
+    GROUPBOX        "Export:",IDC_STATIC,7,7,81,97
+    CONTROL         "&Hidden Nodes",IDC_CHK_HIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,17,67,10
+    CONTROL         "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,29,67,10
+    CONTROL         "&Vertex Colors",IDC_CHK_VCOLORS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,41,67,10
+    CONTROL         "Skin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,53,67,10
+    CONTROL         "&Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,14,65,67,10
+    CONTROL         "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,14,77,67,10
+    CONTROL         "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,14,89,67,10
+    GROUPBOX        "Behaviors:",IDC_STATIC,94,6,101,97
+    CONTROL         "Generate &Strips",IDC_CHK_STRIPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,17,88,10
+    CONTROL         "&Remap Indices",IDC_CHK_REMAP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,29,88,10
+    CONTROL         "Extra Nodes on Mesh",IDC_CHK_EXTRA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,41,88,11
+    CONTROL         "Add User Prop Buffer",IDC_CHK_UPB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,53,88,11
+    CONTROL         "Flatten Hierarchy",IDC_CHK_HIER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,65,88,10
+    CONTROL         "Remove Extra Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,77,88,10
+    CONTROL         "Sort Nodes",IDC_CHK_SORTNODES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,89,88,10
+    CONTROL         "",IDC_SPIN,"SpinnerControl",NOT WS_VISIBLE,193,7,7,10
+    CONTROL         "",IDC_EDIT,"CustEdit",NOT WS_VISIBLE | WS_TABSTOP,194,18,6,10
+    EDITTEXT        IDC_ED_WELDTHRESH,189,30,11,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED
+    LTEXT           "Auto-&Weld",IDC_LBL_WELDTHRESH,192,42,8,8,NOT WS_VISIBLE | WS_DISABLED
+    LTEXT           "Default Texture &Prefix:",IDC_STATIC,7,111,71,8
+    EDITTEXT        IDC_ED_TEXPREFIX,7,122,190,12,ES_AUTOHSCROLL
+    LTEXT           "Game",IDC_STATIC,7,138,66,8
+    COMBOBOX        IDC_CB_GAME,7,149,105,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    LTEXT           "Version",IDC_STATIC,117,138,39,8
+    EDITTEXT        IDC_CB_VERSION,117,149,45,12,ES_AUTOHSCROLL
+    LTEXT           "User",IDC_STATIC,167,138,25,8
+    EDITTEXT        IDC_CB_USER_VERSION,167,149,30,12,ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "&Export",IDOK,5,166,34,14
+    PUSHBUTTON      "&Cancel",IDCANCEL,45,166,33,14
+    LTEXT           "http://niftools.sourceforge.net",IDC_LBL_LINK,105,166,95,14,SS_NOTIFY | SS_CENTERIMAGE
 END
 
 
@@ -129,14 +124,53 @@ BEGIN
     IDD_PANEL, DIALOG
     BEGIN
         LEFTMARGIN, 7
-        RIGHTMARGIN, 193
+        RIGHTMARGIN, 200
         TOPMARGIN, 7
-        BOTTOMMARGIN, 130
+        BOTTOMMARGIN, 180
     END
 END
 #endif    // APSTUDIO_INVOKED
 
 
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,2,0,0
+ PRODUCTVERSION 0,2,0,0
+ FILEFLAGSMASK 0x37L
+#ifdef _DEBUG
+ FILEFLAGS 0x21L
+#else
+ FILEFLAGS 0x20L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "FileDescription", "3ds Max Nif Exporter"
+            VALUE "FileVersion", "0, 2, 0, 0"
+            VALUE "InternalName", "NifExport.dle"
+            VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved."
+            VALUE "OriginalFilename", "NifExport.dle"
+            VALUE "ProductName", "3ds Max Nif Exporter"
+            VALUE "ProductVersion", "0, 2, 0, 0"
+            VALUE "SpecialBuild", "Alpha"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+
 /////////////////////////////////////////////////////////////////////////////
 //
 // String Table
@@ -149,7 +183,7 @@ BEGIN
     IDS_SPIN                "Spin"
 END
 
-#endif    // Englisch (USA) resources
+#endif    // English (U.S.) resources
 /////////////////////////////////////////////////////////////////////////////
 
 
diff --git a/NifExport/NifExport_VC80.vcproj b/NifExport/NifExport_VC80.vcproj
index fc8e25e..dda568d 100644
--- a/NifExport/NifExport_VC80.vcproj
+++ b/NifExport/NifExport_VC80.vcproj
@@ -47,7 +47,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot;"
+				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot; /Zm200"
 				Optimization="2"
 				InlineFunctionExpansion="2"
 				EnableIntrinsicFunctions="true"
@@ -153,7 +153,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot;"
+				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot; /Zm200"
 				Optimization="0"
 				AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib;..\NifCommon"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS"
@@ -250,7 +250,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot;"
+				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot; /Zm200"
 				Optimization="0"
 				AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib;..\NifCommon"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS"
@@ -349,7 +349,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot;"
+				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot; /Zm200"
 				Optimization="2"
 				InlineFunctionExpansion="2"
 				EnableIntrinsicFunctions="true"
@@ -457,7 +457,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot;"
+				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot; /Zm200"
 				Optimization="2"
 				InlineFunctionExpansion="2"
 				EnableIntrinsicFunctions="true"
@@ -563,7 +563,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot;"
+				AdditionalOptions="/LD /FI&quot;$(ProjectDir)pch.h&quot; /Zm200"
 				Optimization="0"
 				AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib;..\NifCommon"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS"
diff --git a/NifExport/Util.cpp b/NifExport/Util.cpp
index c714c70..b310bc0 100755
--- a/NifExport/Util.cpp
+++ b/NifExport/Util.cpp
@@ -234,12 +234,16 @@ struct SortNodeEquivalence
       if (!rhs) return true;
       string ltype = lhs->GetType().GetTypeName();
       string rtype = rhs->GetType().GetTypeName();
-      if (ltype == "NiNode")
+      if (ltype == rtype)
          return false;
-      if (rtype == "NiNode")
+      if (ltype == "bhkCollisionObject")
          return true;
-      if (ltype == rtype)
+      if (rtype == "bhkCollisionObject")
          return false;
+      if (ltype == "NiNode")
+         return false;
+      else if (rtype == "NiNode")
+         return true;
       return (ltype < rtype); 
    }
 };
diff --git a/NifExport/pch.h b/NifExport/pch.h
index f916d52..34cf26c 100755
--- a/NifExport/pch.h
+++ b/NifExport/pch.h
@@ -13,7 +13,8 @@
 #include "istdplug.h"
 #include "iparamb2.h"
 #include "iparamm2.h"
-
+#include "objectParams.h"
+#undef ALPHA_NONE
 
 // niflib/Ref.h' header guard caused havok!
 // near & far 
diff --git a/NifExport/resource.h b/NifExport/resource.h
index 520d8a8..26b1288 100755
--- a/NifExport/resource.h
+++ b/NifExport/resource.h
@@ -25,6 +25,14 @@
 #define IDC_CB_VERSION                  1015
 #define IDC_CB_VERSION2                 1016
 #define IDC_CB_USER_VERSION             1016
+#define IDC_CHK_SKIN                    1017
+#define IDC_CHK_ANIMATION               1018
+#define IDC_CHK_EXTRA                   1019
+#define IDC_CHK_UPB                     1020
+#define IDC_CHK_HIER                    1021
+#define IDC_CHK_REM_BONES               1022
+#define IDC_CHECK7                      1023
+#define IDC_CHK_SORTNODES               1023
 #define IDC_COLOR                       1456
 #define IDC_EDIT                        1490
 #define IDC_SPIN                        1496
@@ -35,7 +43,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        102
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1016
+#define _APS_NEXT_CONTROL_VALUE         1024
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
diff --git a/NifImport/ImportMeshAndSkin.cpp b/NifImport/ImportMeshAndSkin.cpp
index 4cfdc3f..846be26 100644
--- a/NifImport/ImportMeshAndSkin.cpp
+++ b/NifImport/ImportMeshAndSkin.cpp
@@ -365,7 +365,7 @@ bool NifImporter::ImportSkin(ImpNode *node, NiTriBasedGeomRef triGeom)
    vector<NiNodeRef> nifBones = nifSkin->GetBones();
 
    //create a skin modifier and add it
-   Modifier *skinMod = GetSkin(tnode);
+   Modifier *skinMod = GetOrCreateSkin(tnode);
    TriObject *triObject = GetTriObject(tnode->GetObjectRef());
    Mesh& m = triObject->GetMesh();
 
diff --git a/NifImport/ImportMtlAndTex.cpp b/NifImport/ImportMtlAndTex.cpp
index 838ba00..d99faf6 100644
--- a/NifImport/ImportMtlAndTex.cpp
+++ b/NifImport/ImportMtlAndTex.cpp
@@ -16,6 +16,10 @@ HISTORY:
 #include "obj/NiWireframeProperty.h"
 #include "obj/NiAlphaProperty.h"
 #include "obj/NiStencilProperty.h"
+#include "obj/NiShadeProperty.h"
+#include "obj/NiVertexColorProperty.h"
+#include "obj/NiDitherProperty.h"
+#include "obj/NiSpecularProperty.h"
 #include "objectParams.h"
 using namespace Niflib;
 
@@ -26,10 +30,50 @@ Texmap* NifImporter::CreateTexture(TexDesc& desc)
       string filename = texSrc->GetExternalFileName();
       if (bmpMgr->CanImport(filename.c_str())){
          BitmapTex *bmpTex = NewDefaultBitmapTex();
-         bmpTex->SetName(texSrc->GetName().c_str());
+         string name = texSrc->GetName();
+         if (name.empty()) {
+            TCHAR buffer[MAX_PATH];
+            _tcscpy(buffer, PathFindFileName(filename.c_str()));
+            PathRemoveExtension(buffer);
+            name = buffer;
+         }         
+         bmpTex->SetName(name.c_str());
          bmpTex->SetMapName(const_cast<TCHAR*>(FindImage(filename).c_str()));
          bmpTex->SetAlphaAsMono(TRUE);
-         bmpTex->SetAlphaSource(ALPHA_NONE);
+         bmpTex->SetAlphaSource(ALPHA_DEFAULT);
+
+         switch (desc.filterMode)
+         {
+         case FILTER_TRILERP: bmpTex->SetFilterType(FILTER_PYR); break;
+         case FILTER_BILERP:  bmpTex->SetFilterType(FILTER_SAT); break;
+         case FILTER_NEAREST: bmpTex->SetFilterType(FILTER_NADA); break;
+         }
+
+         if (UVGen *uvGen = bmpTex->GetTheUVGen()){
+
+            switch (desc.clampMode)
+            {
+            case WRAP_S_WRAP_T : uvGen->SetTextureTiling(3); break;
+            case WRAP_S_CLAMP_T: uvGen->SetTextureTiling(1); break;
+            case CLAMP_S_WRAP_T: uvGen->SetTextureTiling(2); break;
+            case CLAMP_S_CLAMP_T:uvGen->SetTextureTiling(0); break;
+            }
+
+            if (desc.hasTextureTransform) {
+               if (RefTargetHandle ref = uvGen->GetReference(0)){
+                  TexCoord trans = desc.translation;
+                  TexCoord tiling = desc.tiling;
+                  float wangle = TODEG(desc.wRotation);
+
+                  setMAXScriptValue(ref, "U_Offset", 0, trans.u);
+                  setMAXScriptValue(ref, "V_Offset", 0, trans.v);
+                  setMAXScriptValue(ref, "U_Tiling", 0, tiling.u);
+                  setMAXScriptValue(ref, "V_Tiling", 0, tiling.v);
+                  setMAXScriptValue(ref, "W_Angle", 0, wangle);
+               }
+            }
+         }
+
          return bmpTex;
       }
    }
@@ -45,6 +89,7 @@ bool NifImporter::ImportMaterialAndTextures(ImpNode *node, NiAVObjectRef avObjec
    NiWireframePropertyRef wireRef = SelectFirstObjectOfType<NiWireframeProperty>(props);
    NiAlphaPropertyRef alphaRef = SelectFirstObjectOfType<NiAlphaProperty>(props);
    NiStencilPropertyRef stencilRef = SelectFirstObjectOfType<NiStencilProperty>(props);
+   NiShadePropertyRef shadeRef = SelectFirstObjectOfType<NiShadeProperty>(props);
 
    bool hasTexture = (texRef && matRef);
    if (matRef != NULL){
@@ -52,6 +97,13 @@ bool NifImporter::ImportMaterialAndTextures(ImpNode *node, NiAVObjectRef avObjec
       m->SetName(matRef->GetName().c_str());
       if (showTextures)
          m->SetMtlFlag(MTL_DISPLAY_ENABLE_FLAGS, TRUE);
+
+      // try the civ4 shader first then default back to normal shaders
+      if (ImportCiv4Shader(node, avObject, m)) {
+         gi->GetMaterialLibrary().Add(m);
+         node->GetINode()->SetMtl(m);
+         return true;
+		}
       m->SetAmbient(TOCOLOR(matRef->GetAmbientColor()),0);
       m->SetDiffuse(TOCOLOR(matRef->GetDiffuseColor()),0);
       m->SetSpecular(TOCOLOR(matRef->GetSpecularColor()),0);
@@ -64,19 +116,24 @@ bool NifImporter::ImportMaterialAndTextures(ImpNode *node, NiAVObjectRef avObjec
       m->SetShininess(matRef->GetGlossiness()/100.0,0);
       m->SetOpacity(matRef->GetTransparency(),0);
 
-      bool hasShaderAttributes = (wireRef != NULL) || (stencilRef != NULL);
+      bool hasShaderAttributes = (wireRef != NULL) || (stencilRef != NULL) || (shadeRef != NULL);
       if (m->SupportsShaders() && hasShaderAttributes) {
          if (Shader *s = m->GetShader()) {
             if (wireRef != NULL && (wireRef->GetFlags() & 1)) {
                BOOL value = TRUE;
-               setMAXScriptValue(s->GetReference(0), "wire", 0, value);
+               m->SetWire(value);
             }
             if (stencilRef != NULL) {
-
+               if (stencilRef->GetDrawMode() == 3 /*DRAW_BOTH*/) {
+                  BOOL value = TRUE;
+                  m->SetTwoSided(value);
+               }
+            }
+            if (shadeRef != NULL && shadeRef->GetFlags() & 1) {
+               m->SetFaceted(TRUE);
             }
          }
       }
-      
 
       if (NULL != texRef)
       {
@@ -115,12 +172,150 @@ bool NifImporter::ImportMaterialAndTextures(ImpNode *node, NiAVObjectRef avObjec
    return hasTexture;
 }
 
+bool NifImporter::ImportCiv4Shader(ImpNode *node, NiAVObjectRef avObject, StdMat2 *mtl)
+{
+   if (!useCiv4Shader || !mtl || !mtl->SupportsShaders()) 
+      return false;
+
+   Class_ID civ4Shader(0x670a77d0,0x23ab5c7f);
+   if (!mtl->SwitchShader(civ4Shader))
+      return false;
+
+   TSTR shaderByName;
+   if (Shader *s = mtl->GetShader())
+      s->GetClassName(shaderByName);
+   if (shaderByName != TSTR("CivilizationIV Shader"))
+      return false;
+
+   RefTargetHandle ref = mtl->GetReference(2/*shader*/);
+   if (!ref)
+      return false;
+
+   vector<NiPropertyRef> props = avObject->GetProperties();
+
+   if (NiMaterialPropertyRef matRef = SelectFirstObjectOfType<NiMaterialProperty>(props)){
+      Color ambient = TOCOLOR(matRef->GetAmbientColor());
+      Color diffuse = TOCOLOR(matRef->GetDiffuseColor());
+      Color specular = TOCOLOR(matRef->GetSpecularColor());
+      Color emittance = TOCOLOR(matRef->GetEmissiveColor());
+      float shininess = matRef->GetGlossiness();
+      float alpha = matRef->GetTransparency() * 100.0f;
+
+      mtl->SetShinStr(0.0,0);
+      mtl->SetShininess(shininess/100.0,0);
+      mtl->SetOpacity(alpha*100.0f,0);
+
+      setMAXScriptValue(ref, "ambient", 0, ambient );
+      setMAXScriptValue(ref, "diffuse", 0, diffuse );
+      setMAXScriptValue(ref, "specular", 0, specular );
+      setMAXScriptValue(ref, "emittance", 0, emittance );
+      setMAXScriptValue(ref, "shininess", 0, shininess );
+      setMAXScriptValue(ref, "alpha", 0, alpha );
+   }
+   if (NiShadePropertyRef shadeRef = SelectFirstObjectOfType<NiShadeProperty>(props)) {
+      if (shadeRef->GetFlags() & 1){
+         mtl->SetFaceted(TRUE);
+      }
+   }
+   if (NiWireframePropertyRef wireRef = SelectFirstObjectOfType<NiWireframeProperty>(props)) {
+      if (wireRef->GetFlags() & 1){
+         mtl->SetWire(TRUE);
+      }
+   }
+   if (NiStencilPropertyRef stencilRef = SelectFirstObjectOfType<NiStencilProperty>(props)) {
+      mtl->SetTwoSided(TRUE);
+   }
+   bool Dither = false;
+   bool SpecularEnable = false;
+   if (NiDitherPropertyRef ditherRef = SelectFirstObjectOfType<NiDitherProperty>(props)) {
+      Dither = (ditherRef->GetFlags() & 1) ? true : false;
+   }
+   if (NiSpecularPropertyRef specRef = SelectFirstObjectOfType<NiSpecularProperty>(props)) {
+      SpecularEnable = (specRef->GetFlags() & 1) ? true : false;
+   }
+   setMAXScriptValue(ref, "Dither", 0, Dither );
+   setMAXScriptValue(ref, "SpecularEnable", 0, SpecularEnable);
+
+   if (NiVertexColorPropertyRef vertexColor = SelectFirstObjectOfType<NiVertexColorProperty>(props)) {
+      int SrcVertexMode = vertexColor->GetVertexMode();
+      int LightingMode = vertexColor->GetLightingMode();
+      bool VertexColorsEnable = true;
+      setMAXScriptValue(ref, "Vertex_Color_Enable", 0, VertexColorsEnable);
+      setMAXScriptValue(ref, "SourceVertexMode", 0, SrcVertexMode);
+      setMAXScriptValue(ref, "LightingMode", 0, LightingMode);
+   } else {
+      bool VertexColorsEnable = false;
+      setMAXScriptValue(ref, "Vertex_Color_Enable", 0, VertexColorsEnable);
+   }
+   if (NiAlphaPropertyRef alphaRef = SelectFirstObjectOfType<NiAlphaProperty>(props)) {
+      int TestRef = alphaRef->GetAlphaTestThreshold();
+      int srcBlend = alphaRef->GetSourceBlendMode(); 
+      int destBlend = alphaRef->GetDestBlendMode();
+      int TestMode = alphaRef->GetTestMode();
+      bool AlphaTestEnable = alphaRef->GetAlphaTest();     
+      bool NoSorter = !alphaRef->GetAlphaSort();
+      bool alphaBlend = alphaRef->GetAlphaBlend();
+      int alphaMode = 1;
+
+      if (!alphaBlend) {
+         alphaMode = 1; // none
+      } else if (srcBlend == NiAlphaProperty::BM_SRC_ALPHA && destBlend == NiAlphaProperty::BM_ONE_MINUS_SRC_ALPHA) {
+         alphaMode = 0; // standard or automatic?
+      } else if (srcBlend == NiAlphaProperty::BM_ONE && destBlend == NiAlphaProperty::BM_ONE) {
+         alphaMode = 3;
+      } else if (srcBlend == NiAlphaProperty::BM_ZERO && destBlend == NiAlphaProperty::BM_SRC_COLOR) {
+         alphaMode = 4;
+      } else {
+         alphaMode = 5;
+      }
+      setMAXScriptValue(ref, "AlphaTestEnable", 0, AlphaTestEnable );
+      setMAXScriptValue(ref, "alphaMode", 0, alphaMode);
+      setMAXScriptValue(ref, "srcBlend", 0, srcBlend);
+      setMAXScriptValue(ref, "destBlend", 0, destBlend);
+      setMAXScriptValue(ref, "NoSorter", 0, NoSorter);
+      setMAXScriptValue(ref, "TestRef", 0, TestRef );
+      setMAXScriptValue(ref, "TestMode", 0, TestMode );
+   }
+   if (NiTexturingPropertyRef texRef = SelectFirstObjectOfType<NiTexturingProperty>(props)) {
+      Matrix22 m2 = texRef->GetBumpMapMatrix();
+      float Magnitude = (m2[0][0] + m2[1][1]) / 2.0f;
+      float LumaScale = texRef->GetLumaScale();
+      float LumaOffset = texRef->GetLumaOffset();
+      int ApplyMode = texRef->GetApplyMode();
+
+      setMAXScriptValue(ref, "Bump_Map_Magnitude", 0, Magnitude);
+      setMAXScriptValue(ref, "Bump_Map_Luma_Scale", 0, LumaScale);
+      setMAXScriptValue(ref, "Bump_Map_Luma_offset", 0, LumaOffset);
+      setMAXScriptValue(ref, "ApplyMode", 0, ApplyMode);
+
+      int ntex = mtl->NumSubTexmaps();
+      if (ntex > 0)
+      {
+         ntex = min(ntex, 7);
+         TexType texmap[] = {BASE_MAP, DARK_MAP, DETAIL_MAP, DECAL_0_MAP, BUMP_MAP, GLOSS_MAP, GLOW_MAP, DECAL_1_MAP};
+         NiTexturingPropertyRef texProp = CreateNiObject<NiTexturingProperty>();       
+         texProp->SetApplyMode(Niflib::ApplyMode(ApplyMode));
+         texProp->SetTextureCount(7);
+         for (int i = 0; i < ntex; ++i) {
+            TexType textype = texmap[i];
+            if (texRef->HasTexture(textype)){
+               if (Texmap* tex = CreateTexture(texRef->GetTexture(textype))) {
+                  mtl->SetSubTexmap(i, tex);
+               }
+            }
+         }
+      }
+   }
+   return true;
+}
+
+
 string NifImporter::FindImage(const string& name)
 {
    TCHAR buffer[MAX_PATH];
 
    // Simply check for fully qualified path
-   if (PathIsRoot(name.c_str())) {
+   if (!PathIsRelative(name.c_str())) {
       if (-1 != _taccess(name.c_str(), 0))
          return string(buffer);
    } 
@@ -138,4 +333,6 @@ string NifImporter::FindImage(const string& name)
       return appSettings->FindImage(name);
    }
    return name;
-}
\ No newline at end of file
+}
+
+
diff --git a/NifImport/ImportSkeleton.cpp b/NifImport/ImportSkeleton.cpp
index 885d930..dfc2eb0 100644
--- a/NifImport/ImportSkeleton.cpp
+++ b/NifImport/ImportSkeleton.cpp
@@ -611,10 +611,7 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse)
          else if (bone = CreateBone(name, p, pp, zAxis))
          {
             PosRotScaleNode(bone, p, q, scale, prs);
-            if (isDummy)
-               bone->Hide(TRUE);
-            else
-               bone->Hide(node->GetHidden() ? TRUE : FALSE);
+            bone->Hide(node->GetHidden() ? TRUE : FALSE);
          }
          if (bone)
          {
diff --git a/NifImport/MaxNifImport.cpp b/NifImport/MaxNifImport.cpp
index 40f861f..9af93ff 100644
--- a/NifImport/MaxNifImport.cpp
+++ b/NifImport/MaxNifImport.cpp
@@ -64,44 +64,6 @@ class MaxNifImportClassDesc : public ClassDesc2 {
 static MaxNifImportClassDesc MaxNifImportDesc;
 ClassDesc2* GetMaxNifImportDesc() { return &MaxNifImportDesc; }
 
-BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) {
-	static NifImporter *imp = NULL;
-
-	switch(message) {
-		case WM_INITDIALOG:
-         {
-			   imp = (NifImporter *)lParam;
-			   CenterWindow(hWnd,GetParent(hWnd));
-
-            char buffer[33] = {0};
-            sprintf(buffer, "%f", imp->bipedHeight);
-            SetWindowText(GetDlgItem(hWnd, IDC_EDITHEIGHT), buffer);
-         }
-			return TRUE;
-
-		case WM_CLOSE:
-         {
-            char buffer[33] = {0}, *end = NULL;
-            GetWindowText(GetDlgItem(hWnd, IDC_EDITHEIGHT), buffer, 33);
-            imp->bipedHeight = strtod(buffer, &end);
-			   EndDialog(hWnd, 0);
-         }
-			return TRUE;
-
-      case WM_COMMAND : 
-         {
-            switch (wParam)
-            {
-            case IDCLOSE :
-               SendMessage(hWnd, WM_CLOSE, 0, 0);
-               return TRUE;
-            }
-         }
-         break;
-	}
-	return FALSE;
-}
-
 
 //--- MaxNifImport -------------------------------------------------------
 MaxNifImport::MaxNifImport()
diff --git a/NifImport/MaxNifImport.rc b/NifImport/MaxNifImport.rc
index 06f8df2..639490e 100644
--- a/NifImport/MaxNifImport.rc
+++ b/NifImport/MaxNifImport.rc
@@ -26,14 +26,34 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 // Dialog
 //
 
-IDD_PANEL DIALOGEX 0, 0, 142, 59
+IDD_PANEL DIALOGEX 0, 0, 206, 158
 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 EXSTYLE WS_EX_TOOLWINDOW
+CAPTION "Import Nif"
 FONT 8, "MS Sans Serif", 0, 0, 0x1
 BEGIN
-    EDITTEXT        IDC_EDITHEIGHT,68,15,62,14,ES_AUTOHSCROLL
-    LTEXT           "&Height:",IDC_STATIC,16,18,49,8
-    PUSHBUTTON      "&Close",IDCLOSE,44,38,50,14
+    GROUPBOX        "Import:",IDC_STATIC,7,6,81,81
+    CONTROL         "&Skeleton",IDC_CHK_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,16,67,10
+    CONTROL         "Skin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,27,67,10
+    CONTROL         "&Vertex Colors",IDC_CHK_VCOLORS,"Button",BS_AUTO3STATE | WS_TABSTOP,14,38,67,10
+    CONTROL         "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,62,67,10
+    CONTROL         "&Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,50,67,10
+    CONTROL         "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,73,67,10
+    GROUPBOX        "Behaviors:",IDC_STATIC,94,6,101,81
+    CONTROL         "Flip UV",IDC_CHK_FLIP_UV,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,16,88,10
+    CONTROL         "&Render Textures in View",IDC_CHK_SHOW_TEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,27,88,10
+    CONTROL         "&Auto Smooth Mesh",IDC_CHK_AUTOSMOOTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,38,88,11
+    CONTROL         "Remove Illegal Faces",IDC_CHK_ILLEGAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,50,88,11
+    CONTROL         "Remove Unused Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,62,88,10
+    CONTROL         "&Use Biped",IDC_CHK_BIPED,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,102,73,87,10
+    LTEXT           "Skeleton:",IDC_STC_SKELETON,7,107,31,8
+    EDITTEXT        IDC_ED_SKELETON,7,119,171,12,ES_AUTOHSCROLL
+    PUSHBUTTON      "...",IDC_BTN_BROWSE,180,119,19,13
+    LTEXT           "Game:",IDC_STATIC,7,93,31,8
+    COMBOBOX        IDC_CB_GAME,47,91,131,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+    DEFPUSHBUTTON   "&Import",IDOK,5,137,34,14
+    PUSHBUTTON      "&Cancel",IDCANCEL,45,137,33,14
+    LTEXT           "http://niftools.sourceforge.net",IDC_LBL_LINK,93,137,95,14,SS_NOTIFY | SS_CENTERIMAGE
 END
 
 
@@ -48,9 +68,9 @@ BEGIN
     IDD_PANEL, DIALOG
     BEGIN
         LEFTMARGIN, 7
-        RIGHTMARGIN, 135
+        RIGHTMARGIN, 199
         TOPMARGIN, 7
-        BOTTOMMARGIN, 52
+        BOTTOMMARGIN, 151
     END
 END
 #endif    // APSTUDIO_INVOKED
@@ -88,8 +108,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,1,6,8
- PRODUCTVERSION 0,1,6,0
+ FILEVERSION 0,2,0,0
+ PRODUCTVERSION 0,2,0,0
  FILEFLAGSMASK 0x37L
 #ifdef _DEBUG
  FILEFLAGS 0x21L
@@ -105,12 +125,12 @@ BEGIN
         BLOCK "040904b0"
         BEGIN
             VALUE "FileDescription", "3ds Max Nif Importer"
-            VALUE "FileVersion", "0, 1, 6, 8"
+            VALUE "FileVersion", "0, 2, 0, 0"
             VALUE "InternalName", "MaxNifImport.dli"
             VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved."
             VALUE "OriginalFilename", "MaxNifImport.dli"
             VALUE "ProductName", "3ds Max Nif Importer"
-            VALUE "ProductVersion", "0, 1, 6, 0"
+            VALUE "ProductVersion", "0, 2, 0, 0"
             VALUE "SpecialBuild", "Alpha"
         END
     END
diff --git a/NifImport/MaxNifImport_VC80.vcproj b/NifImport/MaxNifImport_VC80.vcproj
index d05d46e..245bcbb 100644
--- a/NifImport/MaxNifImport_VC80.vcproj
+++ b/NifImport/MaxNifImport_VC80.vcproj
@@ -695,10 +695,6 @@
 				RelativePath=".\KFImporter.h"
 				>
 			</File>
-			<File
-				RelativePath=".\objectParams.h"
-				>
-			</File>
 			<File
 				RelativePath=".\resource.h"
 				>
@@ -788,6 +784,10 @@
 				RelativePath=".\MaxNifImport.h"
 				>
 			</File>
+			<File
+				RelativePath=".\NifDialog.cpp"
+				>
+			</File>
 			<File
 				RelativePath=".\NIFImport.cpp"
 				>
diff --git a/NifImport/NIFImport.cpp b/NifImport/NIFImport.cpp
index b8f9dc9..c728fed 100644
--- a/NifImport/NIFImport.cpp
+++ b/NifImport/NIFImport.cpp
@@ -72,7 +72,7 @@ void NifImporter::Initialize()
 
       hasSkeleton = HasSkeleton();
       isBiped = IsBiped();
-      skeleton = (appSettings != NULL) ? appSettings->Skeleton : "";
+      skeleton = GetSkeleton(appSettings);
       importSkeleton = (appSettings != NULL) ? appSettings->useSkeleton : false;
       importSkeleton &= hasSkeleton;
 
@@ -89,6 +89,22 @@ void NifImporter::Initialize()
    }
 }
 
+string NifImporter::GetSkeleton(AppSettings *appSettings)
+{
+   string skeleton = (appSettings != NULL) ? appSettings->Skeleton : "";
+   // Guess that the skeleton is the same one in the current directory
+   if (importSkeleton && !defaultSkeletonName.empty()) {
+      TCHAR buffer[MAX_PATH];
+      GetFullPathName(name.c_str(), _countof(buffer), buffer, NULL);
+      PathRemoveFileSpec(buffer);
+      PathAddBackslash(buffer);
+      PathAppend(buffer, defaultSkeletonName.c_str());
+      if (-1 != _taccess(buffer, 0))
+         skeleton = buffer;
+   }
+   return skeleton;
+}
+
 void NifImporter::LoadIniSettings()
 {
    TCHAR iniName[MAX_PATH];
@@ -127,6 +143,7 @@ void NifImporter::LoadIniSettings()
    enableSkinSupport = GetIniValue(NifImportSection, "EnableSkinSupport", true);
    enableCollision = GetIniValue(NifImportSection, "EnableCollision", true);
    vertexColorMode = GetIniValue<int>(NifImportSection, "VertexColorMode", 1);
+   useCiv4Shader = GetIniValue(NifImportSection, "UseCiv4Shader", true);
 
    // Biped
    importBones = GetIniValue(BipedImportSection, "ImportBones", true);
@@ -154,7 +171,10 @@ void NifImporter::LoadIniSettings()
 
    // Collision
    bhkScaleFactor = GetIniValue<float>(CollisionSection, "bhkScaleFactor", 7.0f);
-
+   ApplyAppSettings();
+}
+void NifImporter::ApplyAppSettings()
+{
    goToSkeletonBindPosition = false;
    // Override specific settings
    if (appSettings) {
@@ -170,14 +190,22 @@ void NifImporter::LoadIniSettings()
 
 void NifImporter::SaveIniSettings()
 {
-   //SetIniValue(NifImportSection, "UseBiped", useBiped);
-   //SetIniValue<string>(NifImportSection, "Skeleton", skeleton);
-   //SetIniValue<string>(NifImportSection, "SkeletonCheck", skeletonCheck);
-
-   //SetIniValue<float>(BipedImportSection, "BipedHeight", bipedHeight);
-   //SetIniValue<float>(BipedImportSection, "BipedAngle", bipedAngle);
-   //SetIniValue<float>(BipedImportSection, "BipedAnkleAttach", bipedAnkleAttach);
-   //SetIniValue(BipedImportSection, "BipedTrianglePelvis", bipedTrianglePelvis);
+   SetIniValue(NifImportSection, "UseBiped", useBiped);
+   SetIniValue(NifImportSection, "EnableSkinSupport", enableSkinSupport);
+   SetIniValue(NifImportSection, "VertexColorMode", vertexColorMode);
+   SetIniValue(NifImportSection, "EnableCollision", enableCollision);
+   //SetIniValue(NifImportSection, "EnableFurniture", enableAnimations);
+
+   SetIniValue(NifImportSection, "FlipUVTextures", flipUVTextures);
+   SetIniValue(NifImportSection, "ShowTextures", showTextures);
+   SetIniValue(NifImportSection, "EnableAutoSmooth", enableAutoSmooth);
+   SetIniValue(NifImportSection, "RemoveIllegalFaces", removeIllegalFaces);
+   SetIniValue(NifImportSection, "RemoveDegenerateFaces", removeDegenerateFaces);
+
+   SetIniValue(BipedImportSection, "ImportBones", importBones);
+   SetIniValue(BipedImportSection, "RemoveUnusedImportedBones", removeUnusedImportedBones);
+
+   SetIniValue(AnimImportSection, "EnableAnimations", enableAnimations);
 }
 
 INode *NifImporter::GetNode(Niflib::NiNodeRef node)
@@ -190,39 +218,48 @@ INode *NifImporter::GetNode(Niflib::NiNodeRef node)
 bool NifImporter::DoImport()
 {
    bool ok = true;
+   if (!suppressPrompts)
+   {
+      if (!ShowDialog())
+         return true;
+
+      ApplyAppSettings();
+      SaveIniSettings();
+   }
+
    vector<string> importedBones;
    if (!isBiped && importSkeleton && importBones)
    {
-      if (browseForSkeleton)
-      {
-         TCHAR filter[64], *pfilter=filter;
-         pfilter = _tcscpy(filter, shortDescription.c_str());
-         pfilter = _tcscat(pfilter, " (*.NIF)");
-         pfilter += strlen(pfilter);
-         *pfilter++ = '\0';
-         _tcscpy(pfilter, "*.NIF");
-         pfilter += strlen(pfilter);
-         *pfilter++ = '\0';
-         *pfilter++ = '\0';
-
-         TCHAR filename[MAX_PATH];
-         GetFullPathName(skeleton.c_str(), _countof(filename), filename, NULL);
-
-         OPENFILENAME ofn;
-         memset(&ofn, 0, sizeof(ofn));
-         ofn.lStructSize = sizeof(ofn);
-         ofn.hwndOwner = gi->GetMAXHWnd();
-         ofn.lpstrFilter = filter;
-         ofn.lpstrFile = filename;
-         ofn.nMaxFile = _countof(filename);
-         ofn.lpstrTitle = TEXT("Browse for Skeleton NIF...");
-         ofn.lpstrDefExt = TEXT("NIF");
-         ofn.Flags = OFN_HIDEREADONLY|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST;
-         importSkeleton = GetOpenFileName(&ofn) ? true : false;
-         if (importSkeleton) {
-            skeleton = filename;
-         }
-      }
+      //if (browseForSkeleton)
+      //{
+      //   TCHAR filter[64], *pfilter=filter;
+      //   pfilter = _tcscpy(filter, shortDescription.c_str());
+      //   pfilter = _tcscat(pfilter, " (*.NIF)");
+      //   pfilter += strlen(pfilter);
+      //   *pfilter++ = '\0';
+      //   _tcscpy(pfilter, "*.NIF");
+      //   pfilter += strlen(pfilter);
+      //   *pfilter++ = '\0';
+      //   *pfilter++ = '\0';
+
+      //   TCHAR filename[MAX_PATH];
+      //   GetFullPathName(skeleton.c_str(), _countof(filename), filename, NULL);
+
+      //   OPENFILENAME ofn;
+      //   memset(&ofn, 0, sizeof(ofn));
+      //   ofn.lStructSize = sizeof(ofn);
+      //   ofn.hwndOwner = gi->GetMAXHWnd();
+      //   ofn.lpstrFilter = filter;
+      //   ofn.lpstrFile = filename;
+      //   ofn.nMaxFile = _countof(filename);
+      //   ofn.lpstrTitle = TEXT("Browse for Skeleton NIF...");
+      //   ofn.lpstrDefExt = TEXT("NIF");
+      //   ofn.Flags = OFN_HIDEREADONLY|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST;
+      //   importSkeleton = GetOpenFileName(&ofn) ? true : false;
+      //   if (importSkeleton) {
+      //      skeleton = filename;
+      //   }
+      //}
       if (importSkeleton && !skeleton.empty()) {
          NifImporter skelImport(skeleton.c_str(), i, gi, suppressPrompts);
          if (skelImport.isValid())
@@ -233,7 +270,7 @@ bool NifImporter::DoImport()
             // Disable undesirable skeleton items
             skelImport.enableCollision = false;
             skelImport.enableAnimations = false;
-
+            skelImport.suppressPrompts = true;
             skelImport.DoImport();
             if (!skelImport.useBiped && removeUnusedImportedBones)
                importedBones = GetNamesOfNodes(skelImport.nodes);
diff --git a/NifImport/NIFImporter.h b/NifImport/NIFImporter.h
index c15cbf1..4f61b1d 100644
--- a/NifImport/NIFImporter.h
+++ b/NifImport/NIFImporter.h
@@ -15,8 +15,10 @@ HISTORY:
 #define __NIFIMPORTER_H__
 
 #include "BaseImporter.h"
+#include "IniSection.h"
+
 // NIF Importer
-class NifImporter : public BaseImporter
+class NifImporter : public BaseImporter//, public IniFileSection
 {
 public:
    // Ini settings
@@ -30,6 +32,7 @@ public:
    bool goToSkeletonBindPosition;
    bool enableCollision;
    int vertexColorMode;
+   bool useCiv4Shader;
 
    // Biped/Bones related settings
    bool importBones;
@@ -77,6 +80,8 @@ public:
    void LoadIniSettings();
    void SaveIniSettings();
 
+   void ApplyAppSettings();
+
    bool HasSkeleton();
    bool IsBiped();
    void ImportBones(vector<Niflib::NiNodeRef>& bones);
@@ -92,6 +97,7 @@ public:
    bool ImportMesh(Niflib::NiTriShapeRef triShape);
    bool ImportMesh(Niflib::NiTriStripsRef triStrips);
    bool ImportMaterialAndTextures(ImpNode *node, Niflib::NiAVObjectRef avObject);
+   bool ImportCiv4Shader(ImpNode *node, Niflib::NiAVObjectRef avObject, StdMat2 *m);
    bool ImportTransform(ImpNode *node, Niflib::NiAVObjectRef avObject);
    bool ImportMesh(ImpNode *node, TriObject *o, Niflib::NiTriBasedGeomRef triGeom, Niflib::NiTriBasedGeomDataRef triGeomData, vector<Niflib::Triangle>& tris);
    bool ImportVertexColor(ImpNode *node, TriObject *o, Niflib::NiTriBasedGeomRef triGeom, Niflib::NiTriBasedGeomDataRef triGeomData, vector<Niflib::Triangle>& tris);
@@ -105,7 +111,9 @@ public:
    bool ImportCollision(Niflib::NiNodeRef node);
 
    INode *GetNode(Niflib::NiNodeRef node);
+   string GetSkeleton(AppSettings *appSettings);
 
+   bool ShowDialog();
    virtual bool DoImport();
 
    // Animation Helpers
diff --git a/NifImport/NifDialog.cpp b/NifImport/NifDialog.cpp
new file mode 100644
index 0000000..8294625
--- /dev/null
+++ b/NifImport/NifDialog.cpp
@@ -0,0 +1,187 @@
+/**********************************************************************
+*<
+FILE: ImporterCore.cpp
+
+DESCRIPTION:	Core Import helper routines
+
+CREATED BY: tazpn (Theo)
+
+HISTORY: 
+
+*>	Copyright (c) 2006, All Rights Reserved.
+**********************************************************************/
+#include "stdafx.h"
+#include "MaxNifImport.h"
+#include "resource.h"
+#include "shellapi.h"
+
+using namespace Niflib;
+
+BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) {
+   static NifImporter *imp = NULL;
+   static DWORD dlgRes = IDCANCEL; 
+
+   switch(message) {
+      case WM_INITDIALOG:
+         {
+            dlgRes = IDCANCEL;
+
+            // Append file version to dialog
+            TSTR version = GetFileVersion(NULL);
+            if (!version.isNull()) {
+               char buffer[256];
+               GetWindowText(hWnd, buffer, _countof(buffer));
+               _tcscat(buffer, TEXT(" "));
+               _tcscat(buffer, version);
+               SetWindowText(hWnd, buffer);
+            }
+
+            imp = (NifImporter *)lParam;
+            CenterWindow(hWnd,GetParent(hWnd));
+
+            CheckDlgButton(hWnd, IDC_CHK_BONES, imp->importBones);
+            CheckDlgButton(hWnd, IDC_CHK_SKIN, imp->enableSkinSupport);
+            CheckDlgButton(hWnd, IDC_CHK_VCOLORS, imp->vertexColorMode);
+            CheckDlgButton(hWnd, IDC_CHK_COLL, imp->enableCollision);
+            CheckDlgButton(hWnd, IDC_CHK_ANIMATION, imp->enableAnimations);
+            //CheckDlgButton(hWnd, IDC_CHK_FURN, imp->);
+
+            CheckDlgButton(hWnd, IDC_CHK_FLIP_UV, imp->flipUVTextures);
+            CheckDlgButton(hWnd, IDC_CHK_SHOW_TEX, imp->showTextures);
+            CheckDlgButton(hWnd, IDC_CHK_AUTOSMOOTH, imp->enableAutoSmooth);
+            CheckDlgButton(hWnd, IDC_CHK_ILLEGAL, imp->removeIllegalFaces);
+            CheckDlgButton(hWnd, IDC_CHK_REM_BONES, imp->removeUnusedImportedBones);
+            CheckDlgButton(hWnd, IDC_CHK_BIPED, imp->useBiped);
+            
+            string selection = (imp->appSettings) ? imp->appSettings->Name : "User";
+            for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr)
+               SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_ADDSTRING, 0, LPARAM(itr->Name.c_str()));
+            SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_SELECTSTRING, WPARAM(-1), LPARAM(selection.c_str()));
+
+            SHAutoComplete(GetDlgItem(hWnd, IDC_ED_SKELETON), SHACF_FILESYSTEM);
+            if (imp->HasSkeleton() && imp->appSettings && imp->importSkeleton) {
+               SetDlgItemText(hWnd, IDC_ED_SKELETON, imp->skeleton.c_str());
+            } else {
+               EnableWindow(GetDlgItem(hWnd, IDC_STC_SKELETON), FALSE);
+               EnableWindow(GetDlgItem(hWnd, IDC_ED_SKELETON), FALSE);
+               EnableWindow(GetDlgItem(hWnd, IDC_BTN_BROWSE), FALSE);
+               EnableWindow(GetDlgItem(hWnd, IDC_CHK_BIPED), FALSE);
+               EnableWindow(GetDlgItem(hWnd, IDC_CHK_REM_BONES), FALSE);
+            }
+         }
+         return TRUE;
+
+      case WM_CLOSE:
+         {
+            EndDialog(hWnd, dlgRes);
+         }
+         return TRUE;
+
+      case WM_COMMAND : 
+         {
+            if (HIWORD(wParam) == BN_CLICKED)
+            {
+               char tmp[MAX_PATH];
+               switch (LOWORD(wParam))
+               {
+               case IDOK:
+
+                  imp->importBones = IsDlgButtonChecked(hWnd, IDC_CHK_BONES) ? true : false;
+                  imp->enableSkinSupport = IsDlgButtonChecked(hWnd, IDC_CHK_SKIN) ? true : false;
+                  imp->vertexColorMode = (int)IsDlgButtonChecked(hWnd, IDC_CHK_VCOLORS);
+                  imp->enableCollision = IsDlgButtonChecked(hWnd, IDC_CHK_COLL) ? true : false;
+                  imp->enableAnimations = IsDlgButtonChecked(hWnd, IDC_CHK_ANIMATION) ? true : false;
+                  //IsDlgButtonChecked(hWnd, IDC_CHK_FURN, imp->);
+
+                  imp->flipUVTextures = IsDlgButtonChecked(hWnd, IDC_CHK_FLIP_UV) ? true : false;
+                  imp->showTextures = IsDlgButtonChecked(hWnd, IDC_CHK_SHOW_TEX) ? true : false;
+                  imp->enableAutoSmooth = IsDlgButtonChecked(hWnd, IDC_CHK_AUTOSMOOTH) ? true : false;
+                  imp->removeDegenerateFaces =
+                  imp->removeIllegalFaces = IsDlgButtonChecked(hWnd, IDC_CHK_ILLEGAL) ? true : false;
+                  imp->removeUnusedImportedBones = IsDlgButtonChecked(hWnd, IDC_CHK_REM_BONES) ? true : false;
+                  imp->useBiped = IsDlgButtonChecked(hWnd, IDC_CHK_BIPED) ? true : false;
+
+                  GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH);
+                  if (AppSettings *appSettings = FindAppSetting(tmp)) {
+                     imp->appSettings = appSettings;
+                  }
+                  
+                  GetDlgItemText(hWnd, IDC_ED_SKELETON, tmp, MAX_PATH);
+                  imp->skeleton = tmp;
+
+                  EndDialog(hWnd, dlgRes=IDOK);
+                  return TRUE;
+
+               case IDCANCEL:
+                  EndDialog(hWnd, dlgRes=IDCANCEL);
+                  return TRUE;
+
+               case IDC_BTN_BROWSE:
+                  {
+                     TCHAR filter[64], *pfilter=filter;
+                     pfilter = _tcscpy(filter, shortDescription.c_str());
+                     pfilter = _tcscat(pfilter, " (*.NIF)");
+                     pfilter += strlen(pfilter);
+                     *pfilter++ = '\0';
+                     _tcscpy(pfilter, "*.NIF");
+                     pfilter += strlen(pfilter);
+                     *pfilter++ = '\0';
+                     *pfilter++ = '\0';
+
+                     GetDlgItemText(hWnd, IDC_ED_SKELETON, tmp, MAX_PATH);
+                     GetLongPathName(tmp, tmp, _countof(tmp));
+
+                     OPENFILENAME ofn;
+                     memset(&ofn, 0, sizeof(ofn));
+                     ofn.lStructSize = sizeof(ofn);
+                     ofn.hwndOwner = imp->gi->GetMAXHWnd();
+                     ofn.lpstrFilter = filter;
+                     ofn.lpstrFile = tmp;
+                     ofn.nMaxFile = _countof(tmp);
+                     ofn.lpstrTitle = TEXT("Browse for Skeleton NIF...");
+                     ofn.lpstrDefExt = TEXT("NIF");
+                     ofn.Flags = OFN_HIDEREADONLY|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST;
+                     if (GetOpenFileName(&ofn)) {
+                        SetDlgItemText(hWnd, IDC_ED_SKELETON, tmp);
+                     }
+                  }
+                  break;
+               }
+            }
+            else if (HIWORD(wParam) == STN_CLICKED)
+            {
+               if (LOWORD(wParam) == IDC_LBL_LINK)
+               {
+                  ShellExecute(hWnd, "open", "http://niftools.sourceforge.net",
+                     NULL, NULL, SW_SHOWDEFAULT);
+               }
+            }
+            else if (HIWORD(wParam) == CBN_SELCHANGE)
+            {
+               if (LOWORD(wParam) == IDC_CB_GAME)
+               {
+                  char tmp[MAX_PATH];
+                  GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH);
+                  if (AppSettings *appSettings = FindAppSetting(tmp))
+                  {
+                     string skeleton = imp->GetSkeleton(appSettings);
+                     BOOL enable = imp->HasSkeleton() ? TRUE : FALSE;
+                     if (enable) {
+                        SetDlgItemText(hWnd, IDC_ED_SKELETON, skeleton.c_str());
+                     }
+                     EnableWindow(GetDlgItem(hWnd, IDC_STC_SKELETON), enable);
+                     EnableWindow(GetDlgItem(hWnd, IDC_ED_SKELETON), enable);
+                     EnableWindow(GetDlgItem(hWnd, IDC_BTN_BROWSE), enable);
+                  }
+               }
+            }
+         }
+         break;
+   }
+   return FALSE;
+}
+
+bool NifImporter::ShowDialog()
+{
+   return (IDOK == DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), MaxNifImportOptionsDlgProc, (LPARAM)this));
+}
\ No newline at end of file
diff --git a/NifImport/objectParams.h b/NifImport/objectParams.h
deleted file mode 100644
index 23a45f4..0000000
--- a/NifImport/objectParams.h
+++ /dev/null
@@ -1,339 +0,0 @@
-/*===========================================================================*\
- | 
- |  FILE:	objectParams.h
- |			Skeleton project and code for a Utility
- |			3D Studio MAX R3.0
- | 
- |  AUTH:   Cleve Ard
- |			Render Group
- |			Copyright(c) Discreet 2000
- |
- |  HIST:	Started 9-8-00
- | 
-\*===========================================================================*/
-
-#ifndef _OBJECTPARAMS_H_
-#define _OBJECTPARAMS_H_
-
-#include "maxscrpt/maxscrpt.h"
-#include "maxscrpt/Numbers.h"
-#include "maxscrpt/Name.h"
-#include "maxscrpt/ColorVal.h"
-#include "maxscrpt/MAXObj.h"
-#include "assert1.h"
-
-template <class T>
-class ConvertMAXScriptToC;
-inline Value* make_maxscript_value(bool v);
-inline Value* make_maxscript_value(int v);
-inline Value* make_maxscript_value(float v);
-inline Value* make_maxscript_value(COLORREF rgb);
-inline Value* make_maxscript_value(const Color& rgb);
-inline Value* make_maxscript_value(LPCTSTR str);
-inline Value* make_maxscript_value(ReferenceTarget* rtarg);
-
-#if VERSION_3DSMAX <= ((MAX_RELEASE_R7<<16)+(15<<8)+0)
-inline void clear_error_source_data() {}
-#endif
-
-// Not all of the paramters for materials and shaders
-// are published in the interfaces. ObjectParams class
-// is used to access the properties of objects the same
-// way the scriptor does, so you can get to properties.
-
-// Set the array parameter named name to the value at time t.
-template<class T>
-bool setMAXScriptValue(ReferenceTarget* obj, LPTSTR name, TimeValue t, T value, int tabIndex)
-{
-	bool rval = false;					// Return false if fails
-	assert(obj != NULL);
-	init_thread_locals();
-	push_alloc_frame();
-	two_value_locals(prop, result);		// Keep two local variables
-	save_current_frames();
-	trace_back_active = FALSE;
-
-	try {
-		// Get the name of the parameter and then retrieve
-		// the array holding the value we want to set.
-		vl.prop = Name::intern(name);
-		vl.result = MAXWrapper::get_property(obj, vl.prop, NULL);
-
-		// Make sure it is the right type.
-		if (vl.result != NULL && vl.result->tag == class_tag(MAXPB2ArrayParam)) {
-			// OK. Now we make sure the tabIndex is within the array bounds.
-			MAXPB2ArrayParam* array = static_cast<MAXPB2ArrayParam*>(vl.result);
-			if (array->pblock != NULL && array->pdef != NULL
-					&& tabIndex >= 0 && tabIndex < array->pblock->Count(array->pdef->ID)) {
-				// Set the value in the array.
-				array->pblock->SetValue(array->pdef->ID, 0, value, tabIndex);
-				rval = true;		// Succeeded
-			}
-		}
-	} catch ( ... ) {
-		// Failed.
-		clear_error_source_data();
-		restore_current_frames();
-		MAXScript_signals = 0;
-		if (progress_bar_up)
-			MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE;
-	}
-	pop_value_locals();
-	pop_alloc_frame();
-	return rval;
-}
-
-// Set the parameter. Cannot be an array entry
-template<class T>
-bool setMAXScriptValue(ReferenceTarget* obj, LPTSTR name, TimeValue t, T& value)
-{
-	bool rval = false;					// return false if fails
-	assert(obj != NULL);
-	init_thread_locals();
-	push_alloc_frame();
-	two_value_locals(prop, val);			// Keep two local variables
-	save_current_frames();
-	trace_back_active = FALSE;
-
-	try {
-		// Get the name and value to set
-		vl.prop = Name::intern(name);
-		vl.val = make_maxscript_value(value);
-
-		// Set the value.
-		Value* val = MAXWrapper::set_property(obj, vl.prop, vl.val);
-		if (val != NULL)
-			rval = true;				// Succeeded
-	} catch ( ... ) {
-		// Failed.
-		clear_error_source_data();
-		restore_current_frames();
-		MAXScript_signals = 0;
-		if (progress_bar_up)
-			MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE;
-	}
-	pop_value_locals();
-	pop_alloc_frame();
-	return rval;
-}
-
-// Get the parameter from an array
-template<class T>
-bool getMAXScriptValue(ReferenceTarget* obj, LPTSTR name, TimeValue t, T& value, int tabIndex)
-{
-	bool rval = false;					// Return false if fails
-	assert(obj != NULL);
-	init_thread_locals();
-	push_alloc_frame();
-	two_value_locals(prop, result);		// Keep two local variables
-	save_current_frames();
-	trace_back_active = FALSE;
-
-	try {
-		// Get the name and the array holding the roperty.
-		vl.prop = Name::intern(name);
-		vl.result = MAXWrapper::get_property(obj, vl.prop, NULL);
-
-		// Make sure it is they right type.
-		if (vl.result != NULL && is_tab_param(vl.result)) {
-			// OK. Now we make sure the tabIndex is within the array bounds.
-			MAXPB2ArrayParam* array = static_cast<MAXPB2ArrayParam*>(vl.result);
-			if (array->pblock != NULL && array->pdef != NULL
-					&& tabIndex >= 0 && tabIndex < array->pblock->Count(array->pdef->ID)) {
-				// Good. Get the value
-				array->pblock->GetValue(array->pdef->ID, 0, value, Interval(0,0), tabIndex);
-				rval = true;			// Succeeded
-			}
-		}
-	} catch ( ... ) {
-		// Failed.
-		clear_error_source_data();
-		restore_current_frames();
-		MAXScript_signals = 0;
-		if (progress_bar_up)
-			MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE;
-	}
-	pop_value_locals();
-	pop_alloc_frame();
-	return rval;
-}
-
-// Get the parameter
-template<class T>
-bool getMAXScriptValue(ReferenceTarget* obj, LPTSTR name, TimeValue t, T& value)
-{
-	bool rval = false;				// Return false if fails
-	assert(obj != NULL);
-	init_thread_locals();
-	push_alloc_frame();
-	two_value_locals(prop, result);	// Keep two local varaibles
-	save_current_frames();
-	trace_back_active = FALSE;
-
-	try {
-		// Get the name and the parameter value
-		vl.prop = Name::intern(name);
-		vl.result = MAXWrapper::get_property(obj, vl.prop, NULL);
-
-		// Make sure it is valid.
-		if (vl.result != NULL && vl.result != &undefined && vl.result != &unsupplied) {
-			// Convert to C++ type.
-			value = ConvertMAXScriptToC<T>::cvt(vl.result);
-			rval = true;				// Succeeded
-		}
-	} catch ( ... ) {
-		clear_error_source_data();
-		restore_current_frames();
-		MAXScript_signals = 0;
-		if (progress_bar_up)
-			MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE;
-	}
-	pop_value_locals();
-	pop_alloc_frame();
-	return rval;
-}
-
-// Get the parameter controller
-inline Control* getMAXScriptController(ReferenceTarget* obj, LPTSTR name, ParamDimension*& dim)
-{
-	Control* rval = NULL;
-	assert(obj != NULL);
-	init_thread_locals();
-	push_alloc_frame();
-	one_value_local(prop);			// Keep one local varaibles
-	save_current_frames();
-	trace_back_active = FALSE;
-
-	try {
-		// Get the name and the parameter value
-		vl.prop = Name::intern(name);
-		rval = MAXWrapper::get_max_prop_controller(obj, vl.prop, &dim);
-	} catch ( ... ) {
-		clear_error_source_data();
-		restore_current_frames();
-		MAXScript_signals = 0;
-		if (progress_bar_up)
-			MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE;
-	}
-	pop_value_locals();
-	pop_alloc_frame();
-	return rval;
-}
-
-// Set the parameter controller
-inline bool setMAXScriptController(ReferenceTarget* obj, LPTSTR name, Control* control, ParamDimension* dim)
-{
-	bool rval = false;
-	assert(obj != NULL);
-	init_thread_locals();
-	push_alloc_frame();
-	two_value_locals(prop, maxControl);			// Keep two local varaibles
-	save_current_frames();
-	trace_back_active = FALSE;
-
-	try {
-		// Get the name and the parameter value
-		vl.prop = Name::intern(name);
-		vl.maxControl = MAXControl::intern(control, dim);
-		rval = MAXWrapper::set_max_prop_controller(obj, vl.prop,
-			static_cast<MAXControl*>(vl.maxControl)) != 0;
-	} catch ( ... ) {
-		clear_error_source_data();
-		restore_current_frames();
-		MAXScript_signals = 0;
-		if (progress_bar_up)
-			MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE;
-	}
-	pop_value_locals();
-	pop_alloc_frame();
-	return rval;
-}
-
-// These helpers are used to convert C++ values to
-// their MAXScript value. Maxscript uses different
-// methods to handle the conversion, and these helpers
-// allow the conversion to be templated. You may need
-// to add more converter, if you need to access other
-// parameter types.
-inline Value* make_maxscript_value(bool v)
-{
-	return_protected(v ? &true_value : &false_value);
-}
-
-inline Value* make_maxscript_value(int v)
-{
-	return_protected(Integer::intern(v));
-}
-
-inline Value* make_maxscript_value(float v)
-{
-	return_protected(Float::intern(v));
-}
-
-inline Value* make_maxscript_value(COLORREF rgb)
-{
-	return new ColorValue(rgb);
-}
-
-inline Value* make_maxscript_value(const Color& rgb)
-{
-	return new ColorValue(rgb);
-}
-
-inline Value* make_maxscript_value(LPCTSTR str)
-{
-	return Name::intern(const_cast<LPTSTR>(str));
-}
-
-inline Value* make_maxscript_value(ReferenceTarget* rtarg)
-{
-	return MAXClass::make_wrapper_for(rtarg);
-}
-
-// These helpers convert MAXScript values to C++ values.
-// MAXScript uses different methods for this conversion,
-// and these helpers template the conversion. You will
-// need to add more converters if you need more types.
-template <class T>
-class ConvertMAXScriptToC {
-public:
-	static T cvt(Value* val);
-};
-
-inline bool ConvertMAXScriptToC<bool>::cvt(Value* val)
-{
-	return val->to_bool() != 0;
-}
-
-inline int ConvertMAXScriptToC<int>::cvt(Value* val)
-{
-	return val->to_int();
-}
-
-inline float ConvertMAXScriptToC<float>::cvt(Value* val)
-{
-	return val->to_float();
-}
-
-inline Color ConvertMAXScriptToC<Color>::cvt(Value* val)
-{
-	return val->to_point3();
-}
-
-inline LPTSTR ConvertMAXScriptToC<LPTSTR>::cvt(Value* val)
-{
-	return val->to_string();
-}
-
-inline Texmap* ConvertMAXScriptToC<Texmap*>::cvt(Value* val)
-{
-	return val->to_texmap();
-}
-
-inline ReferenceTarget* ConvertMAXScriptToC<ReferenceTarget*>::cvt(Value* val)
-{
-	return val->to_reftarg();
-}
-
-
-#endif
diff --git a/NifImport/resource.h b/NifImport/resource.h
index 01805df..6c53f31 100644
--- a/NifImport/resource.h
+++ b/NifImport/resource.h
@@ -12,9 +12,25 @@
 #define IDC_DOSTUFF                     1000
 #define IDC_EDITHEIGHT                  1001
 #define IDC_BUTTON1                     1002
-#define IDC_COLOR                       1456
-#define IDC_EDIT                        1490
-#define IDC_SPIN                        1496
+#define IDC_BTN_BROWSE                  1002
+#define IDC_CHK_BONES                   1003
+#define IDC_CHK_FLIP_UV                 1004
+#define IDC_CHK_FURN                    1005
+#define IDC_ED_SKELETON                 1006
+#define IDC_CHK_BIPED                   1007
+#define IDC_CHK_COLL                    1010
+#define IDC_LBL_LINK                    1011
+#define IDC_CHK_VCOLORS                 1012
+#define IDC_CHK_SHOW_TEX                1013
+#define IDC_CB_GAME                     1014
+#define IDC_CB_USER_VERSION             1016
+#define IDC_CHK_SKIN                    1017
+#define IDC_CHK_ANIMATION               1018
+#define IDC_CHK_AUTOSMOOTH              1019
+#define IDC_CHK_ILLEGAL                 1020
+#define IDC_STC_SKELETON                1021
+#define IDC_CHK_REM_BONES               1022
+
 
 // Next default values for new objects
 // 
diff --git a/NifPlugins_VC80.sln b/NifPlugins_VC80.sln
index b3f9085..b1ec78f 100644
--- a/NifPlugins_VC80.sln
+++ b/NifPlugins_VC80.sln
@@ -30,6 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 	ProjectSection(SolutionItems) = preProject
 		MaxNifPlugins_Readme.txt = MaxNifPlugins_Readme.txt
 		MaxNifTools.ini = MaxNifTools.ini
+		..\docsys\nif.xml = ..\docsys\nif.xml
 		NifPlugins_Development_Readme.txt = NifPlugins_Development_Readme.txt
 	EndProjectSection
 EndProject
-- 
GitLab