diff --git a/include/niflib.h b/include/niflib.h
index 6e391789f414d29748b0c9802471cdebe93dd8e7..38381caf1a074de87e3dd3e522cdbc65e5da7751 100644
--- a/include/niflib.h
+++ b/include/niflib.h
@@ -209,7 +209,7 @@ NIFLIB_API void WriteNifTree( ostream & stream, Ref<NiObject> const & root, unsi
  * \param export_files What files to write: NIF, NIF + KF + KFM, NIF + KF's + KFM, KF only, KF's only
  * \param kf_type The KF type (Morrowind style, DAoC style, CivIV style, ...)
  */
-NIFLIB_API void WriteFileGroup( string const & file_name, Ref<NiObject> const & root, unsigned int version, ExportOptions export_files, NifGame kf_type );
+NIFLIB_API void WriteFileGroup( string const & file_name, Ref<NiObject> const & root, unsigned int version = VER_4_0_0_2, unsigned int user_version = 0, ExportOptions export_files = EXPORT_NIF, NifGame kf_type = KF_MW);
 
 /*!
  * Creates a clone of an entire tree of objects.
diff --git a/include/obj/NiControllerManager.h b/include/obj/NiControllerManager.h
index 9fa69342d1877eb21b4b115d78610c172413c205..53ed09677e64dc7bc3cbf5008e643761e0ce7a6a 100644
--- a/include/obj/NiControllerManager.h
+++ b/include/obj/NiControllerManager.h
@@ -50,6 +50,9 @@ public:
 	 */
 	vector<Ref<NiControllerSequence > > GetControllerSequences() const;
 	void SetControllerSequences( const vector<Ref<NiControllerSequence > >& value );
+   void AddSequence( Ref<NiControllerSequence > & obj );
+   void RemoveSequence( Ref<NiControllerSequence > obj );
+   void ClearSequences();
 
 	/*!
 	 * Refers to a NiDefaultAVObjectPalette.
diff --git a/include/obj/NiControllerSequence.h b/include/obj/NiControllerSequence.h
index 51a086fe13aceff75a2846fa35d8518d3a3c17fe..0905b62b69b829702e4cf27d8e4baaac0385ed87 100644
--- a/include/obj/NiControllerSequence.h
+++ b/include/obj/NiControllerSequence.h
@@ -139,7 +139,10 @@ public:
 	void SetTargetName( const string & value );
 
 protected:
-	NiControllerManager * NiControllerSequence::Parent() const;
+   friend class NiControllerManager;
+   NiControllerManager * GetParent() const;
+   void SetParent(NiControllerManager *parent);
+
 	NI_CONTROLLER_SEQUENCE_MEMBERS
 	STANDARD_INTERNAL_METHODS
 };
diff --git a/include/obj/NiTriBasedGeom.h b/include/obj/NiTriBasedGeom.h
index 7c6f56f15df16839ea26e1da5b15dccdd73b50e4..66c543e9206a929ddc3b8422a3496593be4b82a8 100644
--- a/include/obj/NiTriBasedGeom.h
+++ b/include/obj/NiTriBasedGeom.h
@@ -47,7 +47,7 @@ public:
 	 * NiSkinInstance and NiSkinData class. The bones must have a common
 	 * ancestor in the scenegraph.  This becomes the skeleton root.
 	 */
-	void BindSkin( vector< Ref<NiNode> > bone_nodes );
+	void BindSkin( vector< Ref<NiNode> > bone_nodes, bool bind_to_scene = false );
 	void UnbindSkin();
 	/*!
 	 * Sets the skin weights in the attached NiSkinData object.
diff --git a/src/niflib.cpp b/src/niflib.cpp
index 8aa16109cd0e7ae166552d2014489d053f01a211..d13542ab58b4e0d3840819fb42bc23cbe3152bea 100644
--- a/src/niflib.cpp
+++ b/src/niflib.cpp
@@ -15,6 +15,7 @@ All rights reserved.  Please see niflib.h for licence. */
 #include "../include/obj/NiAVObject.h"
 #include "../include/obj/NiTextKeyExtraData.h"
 #include "../include/obj/NiSequenceStreamHelper.h"
+#include "../include/obj/NiControllerManager.h"
 #include "../include/obj/NiControllerSequence.h"
 #include "../include/obj/NiStringPalette.h"
 #include "../include/obj/NiSkinPartition.h"
@@ -23,6 +24,9 @@ All rights reserved.  Please see niflib.h for licence. */
 #include "../include/obj/NiInterpolator.h"
 #include "../include/obj/NiKeyframeController.h"
 #include "../include/obj/NiKeyframeData.h"
+#include "../include/obj/NiTransformInterpolator.h"
+#include "../include/obj/NiTransformController.h"
+#include "../include/obj/NiTransformData.h"
 #include "../include/obj/NiStringExtraData.h"
 #include "../include/obj/NiExtraData.h"
 #include "../include/obj/bhkRigidBody.h"
@@ -285,19 +289,8 @@ vector<NiObjectRef> ReadNifList( istream & in ) {
 	return blocks;
 }
 
-// Writes a valid Nif File given a file name, a pointer to the root block of a file tree
-void WriteNifTree( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int user_version ) {
-	//Open output file
-	ofstream out( file_name.c_str(), ofstream::binary );
-
-	WriteNifTree( out, root_block, version, user_version );
-
-	//Close file
-	out.close();
-}
-
-// Writes a valid Nif File given an ostream, a pointer to the root block of a file tree
-void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version, unsigned int user_version ) {
+// Writes a valid Nif File given an ostream, a list to the root objects of a file tree
+void WriteNifTree( ostream & out, list<NiObjectRef> const & roots, unsigned int version, unsigned int user_version ) {
 	// Walk tree, resetting all block numbers
 	//int block_count = ResetBlockNums( 0, root_block );
 	
@@ -305,7 +298,9 @@ void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version
 	map<Type*,uint> type_map;
 	map<NiObjectRef, uint> link_map;
 
-	EnumerateObjects( root, type_map, link_map );
+   for (list<NiObjectRef>::const_iterator it = roots.begin(); it != roots.end(); ++it) {
+	   EnumerateObjects( (*it), type_map, link_map );
+   }
 
 	//Build vectors for reverse look-up
 	vector<NiObjectRef> objects(link_map.size());
@@ -365,22 +360,58 @@ void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version
 	//--Write Footer--//
 	Footer footer;
    footer.numRoots = 0;
-   if (root->IsDerivedType(NiAVObject::TypeConst())) {
-      // Handle most NIF file formats
-      footer.numRoots = 1;
-      footer.roots.resize(1);
-	   footer.roots[0] = StaticCast<NiAVObject>(root);
-   } else if (root->IsDerivedType(NiControllerSequence::TypeConst())) {
-      // KF animation files allow for multiple roots of type NiControllerSequence
-      for ( uint i = 0; i < objects.size(); ++i ) {
-         if (objects[i]->IsDerivedType(NiControllerSequence::TypeConst())) {
-            footer.roots.push_back(objects[i]);
+   if (roots.size() == 1) {
+      const NiObjectRef& root = roots.front();
+      if (root->IsDerivedType(NiAVObject::TypeConst())) {
+         // Handle most NIF file formats
+         footer.numRoots = 1;
+         footer.roots.resize(1);
+	      footer.roots[0] = StaticCast<NiObject>(root);
+      } else if (root->IsDerivedType(NiControllerSequence::TypeConst())) {
+         // KF animation files allow for multiple roots of type NiControllerSequence
+         for ( uint i = 0; i < objects.size(); ++i ) {
+            if (objects[i]->IsDerivedType(NiControllerSequence::TypeConst())) {
+               footer.roots.push_back(objects[i]);
+            }
          }
       }
+   } else {
+      footer.numRoots = roots.size();
+      footer.roots.insert(footer.roots.end(), roots.begin(), roots.end());
    }
 	footer.Write( out, link_map, version, user_version );
 }
 
+// Writes a valid Nif File given a file name, a pointer to the root block of a file tree
+void WriteNifTree( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int user_version ) {
+   //Open output file
+   ofstream out( file_name.c_str(), ofstream::binary );
+
+   list<NiObjectRef> roots;
+   roots.push_back(root_block);
+   WriteNifTree( out, roots, version, user_version );
+
+   //Close file
+   out.close();
+}
+
+void WriteNifTree( string const & file_name, list<NiObjectRef> const & roots, unsigned int version, unsigned int user_version ) {
+   //Open output file
+   ofstream out( file_name.c_str(), ofstream::binary );
+
+   WriteNifTree( out, roots, version, user_version );
+
+   //Close file
+   out.close();
+}
+
+// Writes a valid Nif File given an ostream, a pointer to the root object of a file tree
+void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version, unsigned int user_version ) {
+   list<NiObjectRef> roots;
+   roots.push_back(root);
+   WriteNifTree( out, roots, version, user_version );
+}
+
 void EnumerateObjects( NiObjectRef const & root, map<Type*,uint> & type_map, map<NiObjectRef, uint> & link_map, bool reverse ) {
 	//Ensure that this object has not already been visited
 	if ( link_map.find( root ) != link_map.end() ) {
@@ -500,16 +531,31 @@ list<NiObjectRef> GetAllObjectsByType( NiObjectRef const & root, const Type & ty
 //	return result;
 //};
 
+// Create a valid 
+static std::string CreateFileName(std::string name) {
+   std::string retname = name;
+   std::string::size_type off = 0;
+   std::string::size_type pos = 0;
+   for (;;) {
+      pos = retname.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_^$~!#%&-{}()@'` ", off);
+      if (pos == std::string::npos)
+         break;
+      retname[pos] = '_';
+      off = pos;
+   }
+   return retname;   
+}
+
 //TODO:  This was written by Amorilia.  Figure out how to fix it.
 /*!
  * Helper function to split off animation from a nif tree. If no animation groups are defined, then both xnif_root and xkf_root will be null blocks.
  * \param root_block The root block of the full tree.
- * \param xnif_root The root block of the tree without animation.
- * \param xkf_root The root block of the animation tree.
+ * \param xnif_root The root object of the tree without animation.
+ * \param xkf_roots The root objects of the animation trees.
  * \param kfm The KFM structure (if required by style).
  * \param kf_type What type of keyframe tree to write (Morrowind style, DAoC style, ...).
  */
-void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiObjectRef & xkf_root, Kfm & kfm, int kf_type ) {
+static void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, list<NiObjectRef> & xkf_roots, Kfm & kfm, int kf_type, unsigned int version, unsigned int user_version ) {
 	// Do we have animation groups (a NiTextKeyExtraData block)?
 	// If so, create XNif and XKf trees.
 	NiObjectRef txtkey = GetObjectByType( root_block, NiTextKeyExtraData::TypeConst() );
@@ -520,29 +566,34 @@ void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiOb
 	if ( txtkey_block != NULL ) {
 		if ( kf_type == KF_MW ) {
 			// Construct the XNif file...
-			// We are lazy. (TODO: clone & remove keyframe controllers & keyframe data)
-			xnif_root = root_block;
+
+         xnif_root = CloneNifTree(root_block, version, user_version);
 			
+         // Now search and locate newer timeframe controllers and convert to keyframecontrollers
+         list<NiObjectRef> mgrs = GetAllObjectsByType( xnif_root, NiControllerManager::TypeConst() );
+         for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) {
+            NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it);
+            if ( mgr == NULL ) {
+               continue;
+            }
+            NiObjectNETRef target = mgr->GetTarget();
+            target->RemoveController( StaticCast<NiTimeController>(mgr) );
+            vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences();
+            for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) {
+               NiControllerSequenceRef seq = (*itr);
+               MergeNifTrees(DynamicCast<NiNode>(target), seq, version, user_version);
+            }
+         }
+
 			// Now the XKf file...
 			// Create xkf root header.
 			NiSequenceStreamHelperRef xkf_stream_helper = new NiSequenceStreamHelper;
-			xkf_root = xkf_stream_helper;
-			
-			// Add a copy of the NiTextKeyExtraData block to the XKf header.
-			NiTextKeyExtraDataRef xkf_txtkey_block = new NiTextKeyExtraData;
-
-			//TODO: Have Amorilia fix this
-			xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(xkf_txtkey_block) );
-			
-			//ITextKeyExtraData const *itxtkey_block = QueryTextKeyExtraData(txtkey_block);
-			//ITextKeyExtraData *ixkf_txtkey_block = QueryTextKeyExtraData(xkf_txtkey_block);
-			
-			xkf_txtkey_block->SetKeys( txtkey_block->GetKeys() );
-			
+			xkf_roots.push_back( StaticCast<NiObject>(xkf_stream_helper) );
+					
 			// Append NiNodes with a NiKeyFrameController as NiStringExtraData blocks.
 			list< pair< NiNodeRef, NiKeyframeControllerRef> > node_controllers;
 
-			list<NiObjectRef> nodes = GetAllObjectsByType( root_block, NiNode::TypeConst() );
+			list<NiObjectRef> nodes = GetAllObjectsByType( xnif_root, NiNode::TypeConst() );
 			for ( list<NiObjectRef>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
 				NiNodeRef node = DynamicCast<NiNode>(*it);
 				if ( node == NULL ) {
@@ -552,58 +603,89 @@ void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiOb
 				//Find the first NiKeyframeController in the controller list, if any
 				list<NiTimeControllerRef> controllers = node->GetControllers();
 				NiKeyframeControllerRef key_controller;
-				for ( list<NiTimeControllerRef>::iterator controller = controllers.begin(); controller != controllers.end(); ++controller ) {
-					key_controller = DynamicCast<NiKeyframeController>(*it);
-					if ( key_controller != NULL ) {
-						break;
-					}
+				for ( list<NiTimeControllerRef>::iterator it = controllers.begin(); it != controllers.end(); ++it ) {
+
+               if ((*it)->IsDerivedType(NiKeyframeController::TypeConst())) {
+                  key_controller = StaticCast<NiKeyframeController>(*it);
+               } else if ((*it)->IsDerivedType(NiTransformController::TypeConst())) {
+                  NiTransformControllerRef trans = StaticCast<NiTransformController>(*it);
+                  NiTransformInterpolatorRef interp = DynamicCast<NiTransformInterpolator>(trans->GetInterpolator());
+                  if (interp != NULL) {
+                     NiTransformDataRef transData = interp->GetData();
+                     if (transData != NULL) {
+                        NiKeyframeDataRef data = new NiKeyframeData();
+                        data->SetRotateType( transData->GetRotateType() );
+                        data->SetTranslateType( transData->GetTranslateType() );
+                        data->SetScaleType( transData->GetScaleType() );
+                        data->SetXRotateType( transData->GetXRotateType() );
+                        data->SetYRotateType( transData->GetYRotateType() );
+                        data->SetZRotateType( transData->GetZRotateType() );
+                        data->SetTranslateKeys( transData->GetTranslateKeys() );
+                        data->SetQuatRotateKeys( transData->GetQuatRotateKeys() );
+                        data->SetScaleKeys( transData->GetScaleKeys() );
+                        data->SetXRotateKeys( transData->GetXRotateKeys() );
+                        data->SetYRotateKeys( transData->GetYRotateKeys() );
+                        data->SetZRotateKeys( transData->GetZRotateKeys() );
+
+                        key_controller = new NiKeyframeController();
+                        key_controller->SetFlags( trans->GetFlags() );
+                        key_controller->SetFrequency( trans->GetFrequency() );
+                        key_controller->SetPhase( trans->GetPhase() );
+                        key_controller->SetStartTime( trans->GetStartTime() );
+                        key_controller->SetStopTime( trans->GetStopTime() );
+                        key_controller->SetData( data );
+                        break;
+                     }
+                  }
+               }
 				}
 
 				//If this node has no keyframe controller, put it in the list
 				if ( key_controller != NULL ) {
 					node_controllers.push_back( pair<NiNodeRef,NiKeyframeControllerRef>( node, key_controller ) );
 				}
-			};
-			
+			}
 			
 			for ( list< pair< NiNodeRef, NiKeyframeControllerRef> >::iterator it = node_controllers.begin(); it != node_controllers.end(); ++it ) {
 				//Add string data				
 				NiStringExtraDataRef nodextra = new NiStringExtraData;
 				nodextra->SetData( it->first->GetName() );
-				xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(nodextra) );
-
-				// Add controllers & controller data.
-				NiKeyframeControllerRef controller = it->second;
-				NiKeyframeControllerRef xkf_controller =  new NiKeyframeController;
-
-				xkf_controller->SetFlags( controller->GetFlags() );
-				xkf_controller->SetFrequency( controller->GetFrequency() );
-				xkf_controller->SetPhase( controller->GetPhase() );
-				xkf_controller->SetStartTime( controller->GetStartTime() );
-				xkf_controller->SetStopTime( controller->GetStopTime() );
-				
-				NiKeyframeDataRef xkf_data = new NiKeyframeData;
-				NiKeyframeDataRef kfdata = controller->GetData();
-				xkf_controller->SetData( xkf_data );
-
-				xkf_data->SetRotateType( kfdata->GetRotateType() );
-				xkf_data->SetTranslateType( kfdata->GetTranslateType() );
-				xkf_data->SetScaleType( kfdata->GetScaleType() );
-				xkf_data->SetQuatRotateKeys( kfdata->GetQuatRotateKeys() );
-				xkf_data->SetXRotateKeys( kfdata->GetXRotateKeys() );
-				xkf_data->SetYRotateKeys( kfdata->GetYRotateKeys() );
-				xkf_data->SetZRotateKeys( kfdata->GetZRotateKeys() );
-				xkf_data->SetTranslateKeys( kfdata->GetTranslateKeys() );
-				xkf_data->SetScaleKeys( kfdata->GetScaleKeys() );
-	
+				xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(nodextra), version );
+
+            NiKeyframeControllerRef controller = it->second;
+            (it->first)->RemoveController( StaticCast<NiTimeController>(controller) );
+
 				xkf_stream_helper->AddController( StaticCast<NiTimeController>(controller) );
-			};
-		} else // TODO other games
+			}
+
+			// Add a copy of the NiTextKeyExtraData block to the XKf header.
+			NiTextKeyExtraDataRef xkf_txtkey_block = new NiTextKeyExtraData;
+         xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(xkf_txtkey_block), version );
+			xkf_txtkey_block->SetKeys( txtkey_block->GetKeys() );
+
+      } else if (kf_type == KF_CIV4) {
+         // Construct the Nif file without transform controllers ...
+         xnif_root = CloneNifTree(root_block, version, user_version);
+
+         list<NiObjectRef> mgrs = GetAllObjectsByType( xnif_root, NiControllerManager::TypeConst() );
+         for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) {
+            NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it);
+            if ( mgr == NULL ) {
+               continue;
+            }
+            NiObjectNETRef target = mgr->GetTarget();
+            target->RemoveController( StaticCast<NiTimeController>(mgr) );
+            vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences();
+            for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) {
+               xkf_roots.push_back( StaticCast<NiObject>(*itr) );
+            }
+         }
+
+      } else
 			throw runtime_error("KF splitting for the requested game is not yet implemented.");
 	} else {
 		// no animation groups: nothing to do
-		xnif_root = NULL;
-		xkf_root = NULL;
+		xnif_root = root_block;
 	};
 }
 
@@ -618,7 +700,7 @@ void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiOb
 //};
 
 //TODO:  This was written by Amorilia.  Figure out how to fix it.
-void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, unsigned int version, ExportOptions export_files, NifGame kf_type ) {
+void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int user_version, ExportOptions export_files, NifGame kf_type ) {
 	// Get base filename.
 	uint file_name_slash = uint(file_name.rfind("\\") + 1);
 	string file_name_path = file_name.substr(0, file_name_slash);
@@ -628,23 +710,43 @@ void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, u
 	
 	// Deal with the simple case first
 	if ( export_files == EXPORT_NIF )
-		WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version ); // simply export the NIF file!
+		WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version, user_version ); // simply export the NIF file!
 	// Now consider all other cases
 	else if ( kf_type == KF_MW ) {
 		if ( export_files == EXPORT_NIF_KF ) {
 			// for Morrowind we must also write the full NIF file
-			WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version ); // simply export the NIF file!
+			WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version, user_version ); // simply export the NIF file!
 			NiObjectRef xnif_root;
-			NiObjectRef xkf_root;
+			list<NiObjectRef> xkf_roots;
 			Kfm kfm; // dummy
-			SplitNifTree( root_block, xnif_root, xkf_root, kfm, KF_MW );
-			if ( xnif_root != NULL ) {
-				WriteNifTree( file_name_path + "x" + file_name_base + ".nif", xnif_root, version );
-				WriteNifTree( file_name_path + "x" + file_name_base + ".kf", xkf_root, version );
+			SplitNifTree( root_block, xnif_root, xkf_roots, kfm, kf_type, version, user_version );
+			if ( xnif_root != NULL && !xkf_roots.empty()) {
+				WriteNifTree( file_name_path + "x" + file_name_base + ".nif", xnif_root, version, user_version );
+				WriteNifTree( file_name_path + "x" + file_name_base + ".kf", xkf_roots.front(), version, user_version );
 			};
 		} else
 			throw runtime_error("Invalid export option.");
-	} else
+   } else if (kf_type == KF_CIV4) {
+
+      NiObjectRef xnif_root;
+      list<NiObjectRef> xkf_roots;
+      Kfm kfm; // dummy
+      SplitNifTree( root_block, xnif_root, xkf_roots, kfm, kf_type, version, user_version );
+      if ( export_files == EXPORT_NIF || export_files == EXPORT_NIF_KF || export_files == EXPORT_NIF_KF_MULTI ) {
+         WriteNifTree( file_name_path + file_name_base + ".nif", xnif_root, version, user_version );
+      }
+      if ( export_files == EXPORT_NIF_KF || export_files == EXPORT_KF ) {
+         WriteNifTree( file_name_path + file_name_base + ".kf", xkf_roots, version, user_version );
+      } else if ( export_files == EXPORT_NIF_KF_MULTI || export_files == EXPORT_KF_MULTI ) {
+         for ( list<NiObjectRef>::iterator it = xkf_roots.begin(); it != xkf_roots.end(); ++it ) {
+            NiControllerSequenceRef seq = DynamicCast<NiControllerSequence>(*it);
+            if (seq == NULL)
+               continue;
+            string path = file_name_path + file_name_base + "_" + CreateFileName(seq->GetTargetName()) + "_" + CreateFileName(seq->GetName()) + ".kf";
+            WriteNifTree( path, StaticCast<NiObject>(seq), version, user_version );
+         }         
+      }
+   } else
 		throw runtime_error("Not yet implemented.");
 };
 
@@ -780,7 +882,7 @@ void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence>
 		NiObjectRef tx_clone = txt_key->Clone( version, user_version );
 		NiExtraDataRef ext_dat = DynamicCast<NiExtraData>(tx_clone);
 		if ( ext_dat != NULL ) {
-			target->AddExtraData( ext_dat );
+			target->AddExtraData( ext_dat, version );
 		}
 	}
 
diff --git a/src/obj/NiControllerManager.cpp b/src/obj/NiControllerManager.cpp
index 7dfd00cd9dff960370110855b3f69674b0f50745..8cc85f49732195b9f9a0b05b8c958a18bd5e61bd 100644
--- a/src/obj/NiControllerManager.cpp
+++ b/src/obj/NiControllerManager.cpp
@@ -4,6 +4,7 @@ All rights reserved.  Please see niflib.h for licence. */
 #include "../../include/obj/NiControllerManager.h"
 #include "../../include/obj/NiControllerSequence.h"
 #include "../../include/obj/NiDefaultAVObjectPalette.h"
+#include <algorithm>
 using namespace Niflib;
 
 //Definition of TYPE constant
@@ -50,9 +51,41 @@ vector<Ref<NiControllerSequence > > NiControllerManager::GetControllerSequences(
 }
 
 void NiControllerManager::SetControllerSequences( const vector<Ref<NiControllerSequence > >& value ) {
+   ClearSequences();
 	controllerSequences = value;
+   for (vector<NiControllerSequenceRef>::iterator it = controllerSequences.begin(); it != controllerSequences.end(); ++it) {
+      (*it)->SetParent(this);
+   }
 }
 
+void NiControllerManager::AddSequence( Ref<NiControllerSequence > & obj ) {
+   vector<NiControllerSequenceRef>::iterator begin = controllerSequences.begin();
+   vector<NiControllerSequenceRef>::iterator end = controllerSequences.end();
+   vector<NiControllerSequenceRef>::iterator it = std::find(begin, end, obj);
+   if (it == end) {
+      controllerSequences.insert(end, obj);  
+      obj->SetParent(this);
+   }
+}
+
+void NiControllerManager::RemoveSequence( Ref<NiControllerSequence > obj ) {
+   vector<NiControllerSequenceRef>::iterator begin = controllerSequences.begin();
+   vector<NiControllerSequenceRef>::iterator end = controllerSequences.end();
+   vector<NiControllerSequenceRef>::iterator it = std::find(begin, end, obj);
+   if (it != end) {
+      (*it)->SetParent(NULL);
+      controllerSequences.erase(it);  
+   }
+}
+
+void NiControllerManager::ClearSequences() {
+   for (vector<NiControllerSequenceRef>::iterator it = controllerSequences.begin(); it != controllerSequences.end(); ++it) {
+      (*it)->SetParent(NULL);
+   }
+   controllerSequences.clear();
+}
+
+
 Ref<NiDefaultAVObjectPalette > NiControllerManager::GetObjectPalette() const {
 	return objectPalette;
 }
diff --git a/src/obj/NiControllerSequence.cpp b/src/obj/NiControllerSequence.cpp
index 0abb5c94c024d358880842d7917e56ea50371c69..e0d68c90e821da0947892c4f03535178a3a8a710 100644
--- a/src/obj/NiControllerSequence.cpp
+++ b/src/obj/NiControllerSequence.cpp
@@ -47,7 +47,14 @@ const Type & NiControllerSequence::GetType() const {
 	return TYPE;
 };
 
-NiControllerManager * NiControllerSequence::Parent() const { return NULL; }
+NiControllerManager * NiControllerSequence::GetParent() const { 
+   return manager; 
+}
+
+void NiControllerSequence::SetParent(NiControllerManager * parent) { 
+   manager = parent; 
+}
+
 
 void NiControllerSequence::SetTextKey( const Ref<NiTextKeyExtraData> & txt_key ) {
 	//Set new name
diff --git a/src/obj/NiObjectNET.cpp b/src/obj/NiObjectNET.cpp
index b0b42d350c59280f12220575acbd0514f85916c1..dc039c025a167f6b5866b96e2917ba0dd118c108 100644
--- a/src/obj/NiObjectNET.cpp
+++ b/src/obj/NiObjectNET.cpp
@@ -140,15 +140,19 @@ void NiObjectNET::AddController( Ref<NiTimeController> & obj ) {
 }
 
 void NiObjectNET::RemoveController( Ref<NiTimeController> obj ) {
-	NiTimeControllerRef * cont = &controller;
-	while ( (*cont) != NULL ) {
-		if ( (*cont) == obj ) {
+	for(NiTimeControllerRef last = controller, cont = last, next; cont != NULL; cont = next ) {
+      next = cont->GetNextController();
+		if ( cont == obj ) {
 			//Cut this reference out of the list
-			(*cont)->SetTarget( NULL );
-			(*cont) = (*cont)->GetNextController();
+			cont->SetTarget( NULL );
+         cont->SetNextController( NiTimeControllerRef() );
+         if (cont == controller)
+            controller = next;
+         else
+            last->SetNextController(next);
 		} else {
-			//Advance to the next controller
-			cont = &((*cont)->GetNextController());
+			//Advance last to current controller
+         last = cont;
 		}
 	}
 }
diff --git a/src/obj/NiTriBasedGeom.cpp b/src/obj/NiTriBasedGeom.cpp
index a35d9c2580c27077d431dcb731a2430c5b794526..be4ab01aaa182afd33653486db5efac1072fa28f 100644
--- a/src/obj/NiTriBasedGeom.cpp
+++ b/src/obj/NiTriBasedGeom.cpp
@@ -74,7 +74,7 @@ Ref<NiSkinInstance> NiTriBasedGeom::GetSkinInstance() const {
 	return skinInstance;
 }
 
-void NiTriBasedGeom::BindSkin( vector< Ref<NiNode> > bone_nodes ) {
+void NiTriBasedGeom::BindSkin( vector< Ref<NiNode> > bone_nodes, bool bind_to_scene ) {
 	//Ensure skin is not aleady bound
 	if ( skinInstance != 0 ) {
 		throw runtime_error("You have attempted to re-bind a skin that is already bound.  Unbind it first.");
@@ -110,58 +110,70 @@ void NiTriBasedGeom::BindSkin( vector< Ref<NiNode> > bone_nodes ) {
 		throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
 	}
 
-	NiNodeRef skeleton_root = ancestors[0].front();
-	//Make sure bone and shapes are part of the same tree
-	for ( int i = 1; i < num_lists; ++i ) {
-		if ( ancestors[i].size() == 0 ) {
-			throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
-		}
-		if ( ancestors[i].front() != skeleton_root ) {
-			throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
-		}
-	}
-
-	//Since the first items have been shown to match, pop all the stacks
-	for ( int i = 0; i < num_lists; ++i ) {
-		ancestors[i].pop_front();
-	}
-
-	//Now search for the common ancestor
-
-	while(true) {
-		bool all_same = true;
-		if ( ancestors[0].size() == 0 ) {
-			//This list is over, so the last top is the common ancestor
-			//break out of the loop
-			break;
-		}
-		NiNodeRef first_ancestor = ancestors[0].front();
-		for ( int i = 1; i < num_lists; ++i ) {
-			if ( ancestors[i].size() == 0 ) {
-				//This list is over, so the last top is the common ancestor
-				//break out of the loop
-				all_same = false;
-				break;
-			}
-			if ( ancestors[i].front() != first_ancestor ) {
-				all_same = false;
-			}
-		}
+	NiNodeRef skeleton_root;
+   if (bind_to_scene) {
+      // Just parent to the scene
+      NiNodeRef parent = GetParent();
+      while (parent != NULL) {
+         skeleton_root = parent;
+         parent = parent->GetParent();
+      }
 
-		if ( all_same == true ) {
-			//They're all the same, so set the top, pop all the stacks
-			//and look again
-			
-			skeleton_root = ancestors[0].front();
-			for ( int i = 0; i < num_lists; ++i ) {
-				ancestors[i].pop_front();
-			}
-		} else {
-			//One is different, so the last top is the common ancestor.
-			//break out of the loop
-			break;
-		}
-	}
+   } else {
+      skeleton_root = ancestors[0].front();
+
+	   //Make sure bone and shapes are part of the same tree
+	   for ( int i = 1; i < num_lists; ++i ) {
+		   if ( ancestors[i].size() == 0 ) {
+			   throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
+		   }
+		   if ( ancestors[i].front() != skeleton_root ) {
+			   throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
+		   }
+	   }
+
+	   //Since the first items have been shown to match, pop all the stacks
+	   for ( int i = 0; i < num_lists; ++i ) {
+		   ancestors[i].pop_front();
+	   }
+
+	   //Now search for the common ancestor
+
+	   while(true) {
+		   bool all_same = true;
+		   if ( ancestors[0].size() == 0 ) {
+			   //This list is over, so the last top is the common ancestor
+			   //break out of the loop
+			   break;
+		   }
+		   NiNodeRef first_ancestor = ancestors[0].front();
+		   for ( int i = 1; i < num_lists; ++i ) {
+			   if ( ancestors[i].size() == 0 ) {
+				   //This list is over, so the last top is the common ancestor
+				   //break out of the loop
+				   all_same = false;
+				   break;
+			   }
+			   if ( ancestors[i].front() != first_ancestor ) {
+				   all_same = false;
+			   }
+		   }
+
+		   if ( all_same == true ) {
+			   //They're all the same, so set the top, pop all the stacks
+			   //and look again
+   			
+			   skeleton_root = ancestors[0].front();
+			   for ( int i = 0; i < num_lists; ++i ) {
+				   ancestors[i].pop_front();
+			   }
+		   } else {
+			   //One is different, so the last top is the common ancestor.
+			   //break out of the loop
+			   break;
+		   }
+	   }
+   }
 
 	if ( skeleton_root == NULL ) {
 		throw runtime_error("Failed to find suitable skeleton root.");