From 5d96347ad37a3445672e1c9968a1540ae8cc578d Mon Sep 17 00:00:00 2001
From: Shon Ferguson <shonferg@users.sourceforge.net>
Date: Sun, 25 Jun 2006 00:23:30 +0000
Subject: [PATCH] Implemented NiStringPalette and NiControllerSequence.

---
 obj/NiControllerSequence.cpp | 223 ++++++++++-------------------------
 obj/NiControllerSequence.h   |  15 +--
 obj/NiStringPalette.cpp      |  39 ++++++
 obj/NiStringPalette.h        |   5 +
 4 files changed, 114 insertions(+), 168 deletions(-)

diff --git a/obj/NiControllerSequence.cpp b/obj/NiControllerSequence.cpp
index 912dbbcf..cc2e79d3 100644
--- a/obj/NiControllerSequence.cpp
+++ b/obj/NiControllerSequence.cpp
@@ -14,6 +14,10 @@ All rights reserved.  Please see niflib.h for licence. */
 #include "NiControllerManager.h"
 #include "NiStringPalette.h"
 #include "NiTimeController.h"
+#include "NiSingleInterpolatorController.h"
+#include "NiObjectNET.h"
+#include "NiProperty.h"
+#include "NiStringPalette.h"
 using namespace Niflib;
 
 //Definition of TYPE constant
@@ -49,188 +53,89 @@ const Type & NiControllerSequence::GetType() const {
 
 NiControllerManager * NiControllerSequence::Parent() const { return NULL; }
 
-void NiControllerSequence::SetTextKey( const string new_name, const Ref<NiTextKeyExtraData> & txt_key ) {
+void NiControllerSequence::SetTextKey( const Ref<NiTextKeyExtraData> & txt_key ) {
 	//Set new name
-	textKeysName = new_name;
+	textKeysName = txt_key->GetName();
 	textKeys = txt_key;
 }
 
-void NiControllerSequence::AddController( const string target_name, const Ref<NiTimeController> & obj ) {
+void NiControllerSequence::AddController( const Ref<NiTimeController> & obj ) {
 	//Make sure the link isn't null
 	if ( obj == NULL ) {
 		throw runtime_error("Attempted to add a null controller to NiControllerSequence block.");
 	}
 
-	throw runtime_error("The AddController function cannot be implemented until prolems in the XML are solved.");
-	//TODO:  ControllerLinks should store controllers, not interpolators.  Cannot implement this.
-	//KfChild kc;
+	NiObjectNETRef target = obj->GetTarget();
+	if ( target == NULL ) {
+		throw runtime_error("Controller must have a target to be added to a NiControllerSequence.");
+	}
 
-	
-	//kc.block = new_link;
-
-	////Check for a string palette
-	//blk_ref str_pal = GetAttr("String Palette")->asLink();
-	//if ( str_pal.is_null() == true ) {
-	//	//No string palette, store name internally
-	//	kc.name = new_name;
-	//} else {
-	//	//String palette exists - store name and controller type there
-
-	//	//Make sure they didn't give us empty strings
-	//	if ( new_name.size() == 0 || controller_type.size() == 0 ) {
-	//		throw runtime_error( "You cannot use empty name or controller type strings when using a string palette.");
-	//	}
-
-	//	//Get palette
-	//	string pal = str_pal->GetAttr("Palette")->asString();
-
-	//	//--Search for copies of the text we want to add--//
-
-	//	//Search for the name string
-	//	int offset = (int)pal.find( new_name );
-	//	if ( offset == -1 ) {
-	//		//String not found, append it
-	//		kc.name_offset = (uint)pal.size();
-	//		pal.append( new_name + '\0' );
-	//	} else {
-	//		//String found, use existing offset
-	//		kc.name_offset = offset;
-	//	}
-
-	//	//Search for the controller type string
-	//	offset = (int)pal.find( controller_type );
-	//	if ( offset == -1 ) {
-	//		//String not found, append it
-	//		kc.controller_offset = (uint)pal.size();
-	//		pal.append( controller_type + '\0' );
-	//	} else {
-	//		//String found, use existing offset
-	//		kc.controller_offset = offset;
-	//	}
-
-	//	//Store the palette back to the string pal block
-	//	str_pal->GetAttr("Palette")->Set( pal );
-	//}
-	//
-	//children.push_back( kc );
-
-	////Add new child
-	//AddChild( kc.block.get_block() );
-	//
-	////This should be impossible now, but don't want to forget it later
-	//if ( kc.unk_link.is_null() != true ) {
-	//	AddChild( kc.unk_link.get_block() );
-	//}
+	//Make a new ControllerLink and fill out necessary data
+	ControllerLink cl;
+	cl.controller = obj;
+	cl.targetName = target->GetName();
+	cl.nodeName = target->GetName();
+
+	NiPropertyRef prop = DynamicCast<NiProperty>(target);
+	if ( prop != NULL ) {
+		cl.propertyType = prop->GetType().GetTypeName();
+	}
+
+	cl.controllerType = obj->GetType().GetTypeName();
+
+	//Add finished ControllerLink to list
+	controlledBlocks.push_back( cl );
 }
 
-void NiControllerSequence::AddInterpolator( const string target_name, const Ref<NiInterpolator> & obj, string controller_type ) {
+void NiControllerSequence::AddInterpolator( const Ref<NiSingleInterpolatorController> & obj, byte priority ) {
 	//Make sure the link isn't null
 	if ( obj == NULL ) {
-		throw runtime_error("Attempted to add a null interpolator to NiControllerSequence block.");
+		throw runtime_error("Attempted to add a null controller to NiControllerSequence block.");
 	}
 
-	throw runtime_error("The AddInterpolator function cannot be implemented until prolems in the XML are solved.");
+	NiInterpolatorRef interp = obj->GetInterpolator();
+	if ( interp == NULL ) {
+		throw runtime_error("Controller must have an interpolator attached to be added to a NiControllerSequence with the AddInterpolator function.");
+	}
+
+	NiObjectNETRef target = obj->GetTarget();
+	if ( target == NULL ) {
+		throw runtime_error("Controller must have a target to be added to a NiControllerSequence.");
+	}
 
-	//TODO: Hold off on this until the XML for this block is fixed up.
-	//KfChild kc;
-
-	//kc.block = new_link;
-
-	////Check for a string palette
-	//blk_ref str_pal = GetAttr("String Palette")->asLink();
-	//if ( str_pal.is_null() == true ) {
-	//	//No string palette, store name internally
-	//	kc.name = new_name;
-	//} else {
-	//	//String palette exists - store name and controller type there
-
-	//	//Make sure they didn't give us empty strings
-	//	if ( new_name.size() == 0 || controller_type.size() == 0 ) {
-	//		throw runtime_error( "You cannot use empty name or controller type strings when using a string palette.");
-	//	}
-
-	//	//Get palette
-	//	string pal = str_pal->GetAttr("Palette")->asString();
-
-	//	//--Search for copies of the text we want to add--//
-
-	//	//Search for the name string
-	//	int offset = (int)pal.find( new_name );
-	//	if ( offset == -1 ) {
-	//		//String not found, append it
-	//		kc.name_offset = (uint)pal.size();
-	//		pal.append( new_name + '\0' );
-	//	} else {
-	//		//String found, use existing offset
-	//		kc.name_offset = offset;
-	//	}
-
-	//	//Search for the controller type string
-	//	offset = (int)pal.find( controller_type );
-	//	if ( offset == -1 ) {
-	//		//String not found, append it
-	//		kc.controller_offset = (uint)pal.size();
-	//		pal.append( controller_type + '\0' );
-	//	} else {
-	//		//String found, use existing offset
-	//		kc.controller_offset = offset;
-	//	}
-
-	//	//Store the palette back to the string pal block
-	//	str_pal->GetAttr("Palette")->Set( pal );
-	//}
-	//
-	//children.push_back( kc );
-
-	////Add new child
-	//AddChild( kc.block.get_block() );
-	//
-	////This should be impossible now, but don't want to forget it later
-	//if ( kc.unk_link.is_null() != true ) {
-	//	AddChild( kc.unk_link.get_block() );
-	//}
+	//If there are existing ControllerLinks, use the same StringPalette they're using
+	NiStringPaletteRef str_pal;
+	if ( controlledBlocks.size() > 0 ) {
+		str_pal = controlledBlocks[0].stringPalette;
+	} else {
+		//No existing ones, so make a new one
+		str_pal = new NiStringPalette;
+	}
+
+	//Make a new ControllerLink and fill out necessary data
+	ControllerLink cl;
+
+	cl.interpolator = interp;
+	cl.priority_ = priority;
+	cl.nodeNameOffset = str_pal->AddSubStr( target->GetName() );
+
+	NiPropertyRef prop = DynamicCast<NiProperty>(target);
+	if ( prop != NULL ) {
+		cl.propertyTypeOffset = str_pal->AddSubStr( prop->GetType().GetTypeName() );
+	}
+
+	cl.controllerTypeOffset = str_pal->AddSubStr( obj->GetType().GetTypeName() );
+
+	//Add finished ControllerLink to list
+	controlledBlocks.push_back( cl );
 }
 
 void NiControllerSequence::ClearChildren() {
 	
 	throw runtime_error("The AddInterpolator function cannot be implemented until prolems in the XML are solved.");
 
-	//TODO: Hold off on this until the XML is sorted out
-	////Cycle through all Kf Children, removing them as parents from the blocks they refer to
-	//for (uint i = 0; i < children.size(); ++i ) {
-	//	if ( children[i].block.is_null() != true ) {
-	//		RemoveChild( children[i].block.get_block() );
-	//	}
-	//	if ( children[i].unk_link.is_null() != true ) {
-	//		RemoveChild( children[i].unk_link.get_block() );
-	//	}
-	//}
-
-	////Clear list
-	//children.clear();
-
-	////Check for a string palette
-	//blk_ref str_pal = GetAttr("String Palette")->asLink();
-	//if ( str_pal.is_null() == false ) {
-	//	//There's a string palette, so clear it out
-	//	str_pal->GetAttr("Palette")->Set( "" );
-	//}
+	//Clear list
+	controlledBlocks.clear();
 }
 
-string NiControllerSequence::GetSubStr( const string & pal, short offset ) const {
-	string out;
-	
-	// -1 is a null offset
-	if ( offset == -1 ) {
-		return out;
-	}
-
-	for ( uint i = offset; i < pal.size(); ++i ) {
-		if ( pal[i] == '\0' ) {
-			break;
-		}
-		out.push_back( pal[i] );
-	}
 
-	return out;
-}
diff --git a/obj/NiControllerSequence.h b/obj/NiControllerSequence.h
index 75fed2cc..026042e0 100644
--- a/obj/NiControllerSequence.h
+++ b/obj/NiControllerSequence.h
@@ -15,6 +15,7 @@ class NiTextKeyExtraData;
 class NiControllerManager;
 class NiStringPalette;
 class NiTimeController;
+class NiSingleInterpolatorController;
 
 #include "../gen/obj_defines.h"
 
@@ -47,30 +48,26 @@ public:
 	 * \param txt_key A reference to the NiTextKeyExtraData object to use.
 	 * \sa NiTextKeyExtraData
 	 */
-	void SetTextKey( const string new_name, const Ref<NiTextKeyExtraData> & txt_key );
+	void SetTextKey( const Ref<NiTextKeyExtraData> & txt_key );
 
 	/*! Attatches a controler to this KF file for a KF file of version 10.2.0.0 or below.  Versions above this use interpolators.
-	 * \param target_name The name to re-link this controller with when it is merged with a Nif file.
 	 * \param obj A reference to the new NiTimeController to attach.
 	 * \sa NiControllerSequence::ClearChildren, NiControllersequence::AddInterpolator
 	 */
-	void AddController( const string target_name, const Ref<NiTimeController> & obj );
+	void AddController( const Ref<NiTimeController> & obj );
 
 	/*! Attatches an interpolator to this KF file for a KF file of version greater than 10.2.0.0.  Versions below this use controllers.
-	 * \param target_name The name to re-link this interpolator with when it is merged with a Nif file.
-	 * \param obj A reference to the new NiInterpolator to attach.
-	 * \param controller_type The original controller type that this interpolator was connected to.
+	 * \param obj A reference to the new controller which has an interpolator to attach.
+	 * \param priority Used only in Oblivion to set the priority of one controller over another when the two are merged.
 	 * \sa NiControllerSequence::ClearChildren, NiControllerSequence::AddController
 	 */
-	void AddInterpolator( const string target_name, const Ref<NiInterpolator> & obj, string controller_type );
+	void AddInterpolator( const Ref<NiSingleInterpolatorController> & obj, byte priority = 0 );
 
 	/*! Removes all controllers and interpolators from this Kf file root object.
 	 * \sa NiControllerSequence::AddController, NiControllersequence::AddInterpolator
 	 */
 	void ClearChildren();
 
-private:
-	string GetSubStr( const string & pal, short offset ) const;
 protected:
 	NiControllerManager * NiControllerSequence::Parent() const;
 	NI_CONTROLLER_SEQUENCE_MEMBERS
diff --git a/obj/NiStringPalette.cpp b/obj/NiStringPalette.cpp
index e56baf26..25aa2cb7 100644
--- a/obj/NiStringPalette.cpp
+++ b/obj/NiStringPalette.cpp
@@ -36,3 +36,42 @@ const Type & NiStringPalette::GetType() const {
 	return TYPE;
 };
 
+string NiStringPalette::GetPaletteString() const {
+	return palette.palette;
+}
+	
+void NiStringPalette::SetPaletteString( const string & n ) {
+	palette.palette = n;
+}
+
+string NiStringPalette::GetSubStr( short offset ) const {
+	string out;
+	
+	// -1 is a null offset
+	if ( offset == -1 ) {
+		return out;
+	}
+
+	for ( uint i = offset; i < palette.palette.size(); ++i ) {
+		if ( palette.palette[i] == '\0' ) {
+			break;
+		}
+		out.push_back( palette.palette[i] );
+	}
+
+	return out;
+}
+
+unsigned int NiStringPalette::AddSubStr( const string & n ) {
+	//Search for the string
+	uint offset = (uint)palette.palette.find( n );
+	
+	//If string was not found, append it
+	if ( offset == 0xFFFFFFFF ) {
+		offset = (uint)palette.palette.size();
+		palette.palette.append( n + '\0' );
+	}
+
+	//Return the offset where the string was found or appended
+	return offset;
+}
\ No newline at end of file
diff --git a/obj/NiStringPalette.h b/obj/NiStringPalette.h
index 628f0a47..423ebadd 100644
--- a/obj/NiStringPalette.h
+++ b/obj/NiStringPalette.h
@@ -38,6 +38,11 @@ public:
 	virtual list<NiObjectRef> GetRefs() const;
 	virtual const Type & GetType() const;
 
+	string GetPaletteString() const;
+	void SetPaletteString( const string & n );
+	string GetSubStr( short offset ) const;
+	unsigned int AddSubStr( const string & n );
+
 protected:
 	NI_STRING_PALETTE_MEMBERS
 	STANDARD_INTERNAL_METHODS
-- 
GitLab