diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp
index e630c1118bc859c71c8c0911e3ceb6ec0d0a144b..e5e502b158fd72b3d7e3bc4bfce10bc9635d1da6 100755
--- a/indra/llappearance/lldriverparam.cpp
+++ b/indra/llappearance/lldriverparam.cpp
@@ -110,6 +110,14 @@ void LLDriverParamInfo::toStream(std::ostream &out)
 
 	out << std::endl;
 
+	// FIXME - this mDriverParam backlink makes no sense, because the
+	// LLDriverParamInfos are static objects - there's only one copy
+	// for each param type, so the backlink will just reference the
+	// corresponding param in the most recently created
+	// avatar. Apparently these toStream() methods are not currently
+	// used anywhere, so it's not an urgent problem.
+    LL_WARNS_ONCE() << "Invalid usage of mDriverParam." << LL_ENDL;
+    
 	if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() &&
 		mDriverParam->getAvatarAppearance()->isValid())
 	{
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 22df9c43d7c93d1429ae893c2c84fd3aa5c046e1..37c5e84347eee4e83b8c6d17ff5df202ec8ae8e3 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -216,7 +216,7 @@ struct LLTextureMaskData
  **/
 
 
-struct LLAppearanceMessageContents
+struct LLAppearanceMessageContents: public LLRefCount
 {
 	LLAppearanceMessageContents():
 		mAppearanceVersion(-1),
@@ -1804,42 +1804,55 @@ void LLVOAvatar::buildCharacter()
 //-----------------------------------------------------------------------------
 // resetSkeleton()
 //-----------------------------------------------------------------------------
-void LLVOAvatar::resetSkeleton()
+void LLVOAvatar::resetVisualParams()
 {
-    LL_DEBUGS("Avatar") << avString() << LL_ENDL;
-
-    // Stop all animations
-
-    // Clear all attachment pos overrides
-    clearAttachmentPosOverrides();
-
-    // Preserve state of tweakable params
-    
-    // Reset all params to default state, without propagating changes downstream.
+#if 0
 	for (LLVisualParam *param = getFirstVisualParam(); 
 		param;
 		param = getNextVisualParam())
 	{
-#if 0
 		if (param->isAnimating())
 		{
 			continue;
 		}
         param->setLastWeight(param->getDefaultWeight());
-#endif
 	}
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// resetSkeleton()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::resetSkeleton()
+{
+    LL_DEBUGS("Avatar") << avString() << LL_ENDL;
+    if (!mLastProcessedAppearance)
+    {
+        LL_WARNS() << "Can't reset avatar; no appearance message has been received yet." << LL_ENDL;
+        return;
+    }
+
+    // Stop all animations
+
+    // Clear all attachment pos overrides
+    clearAttachmentPosOverrides();
+
+    // Reset all params to default state, without propagating changes downstream.
+    resetVisualParams();
 
     // Reset all bones and collision volumes to their initial skeleton state.
 	if( !buildSkeleton(sAvatarSkeletonInfo) )
     {
         LL_ERRS() << "Error resetting skeleton" << LL_ENDL;
 	}
+    // Reset attachment points
+    bool ignore_hud_joints = true;
+    initAttachmentPoints(ignore_hud_joints);
 
     // Reset tweakable params to preserved state
     // Apply params
-#if 0
+    applyParsedAppearanceMessage(*mLastProcessedAppearance);
     updateVisualParams();
-#endif
 
     // Restore attachment pos overrides
     rebuildAttachmentPosOverrides();
@@ -5728,87 +5741,99 @@ BOOL LLVOAvatar::loadSkeletonNode ()
 		return FALSE;
 	}
 	
-	// ATTACHMENTS
-	{
-		LLAvatarXmlInfo::attachment_info_list_t::iterator iter;
-		for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
-			 iter != sAvatarXmlInfo->mAttachmentInfoList.end(); 
-			 ++iter)
-		{
-			LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter;
-			if (!isSelf() && info->mJointName == "mScreen")
-			{ //don't process screen joint for other avatars
-				continue;
-			}
+    bool ignore_hud_joints = false;
+    initAttachmentPoints(ignore_hud_joints);
 
-			LLViewerJointAttachment* attachment = new LLViewerJointAttachment();
-			attachment->setName(info->mName);
-			LLJoint *parent_joint = getJoint(info->mJointName);
-            if (!parent_joint)
-            {
-                // If the intended parent for attachment point is unavailable, avatar_lad.xml is corrupt.
-				LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL;
-				LL_ERRS() << "Invalid avatar_lad.xml file" << LL_ENDL;
-                // If we wanted to continue from this case, we could do:
-				//delete attachment;
-                //continue;
-                // but there's no point.
-            }
-			if (info->mHasPosition)
-			{
-				attachment->setOriginalPosition(info->mPosition);
-                attachment->setDefaultPosition(info->mPosition);
-			}
-			
-			if (info->mHasRotation)
-			{
-				LLQuaternion rotation;
-				rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD,
-								 info->mRotationEuler.mV[VY] * DEG_TO_RAD,
-								 info->mRotationEuler.mV[VZ] * DEG_TO_RAD);
-				attachment->setRotation(rotation);
-			}
+	return TRUE;
+}
 
-			int group = info->mGroup;
-			if (group >= 0)
-			{
-				if (group < 0 || group > 9)
-				{
-					LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL;
-				}
-				else
-				{
-					attachment->setGroup(group);
-				}
-			}
+//-----------------------------------------------------------------------------
+// initAttachmentPoints(): creates attachment points if needed, sets state based on avatar_lad.xml. 
+//-----------------------------------------------------------------------------
+void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints)
+{
+    LLAvatarXmlInfo::attachment_info_list_t::iterator iter;
+    for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
+         iter != sAvatarXmlInfo->mAttachmentInfoList.end(); 
+         ++iter)
+    {
+        LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter;
+        if (info->mIsHUDAttachment && (!isSelf() || ignore_hud_joints))
+        {
+		    //don't process hud joint for other avatars, or when doing a skeleton reset.
+            continue;
+        }
 
-			S32 attachmentID = info->mAttachmentID;
-			if (attachmentID < 1 || attachmentID > 255)
-			{
-				LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL;
-				delete attachment;
-				continue;
-			}
-			if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end())
-			{
-				LL_WARNS() << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << LL_ENDL;
-				delete attachment;
-				continue;
-			}
+        S32 attachmentID = info->mAttachmentID;
+        if (attachmentID < 1 || attachmentID > 255)
+        {
+            LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL;
+            continue;
+        }
 
-			attachment->setPieSlice(info->mPieMenuSlice);
-			attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson);
-			attachment->setIsHUDAttachment(info->mIsHUDAttachment);
-			// attachment can potentially be animated, needs a number.
-            attachment->setJointNum(mSkeleton.size() + attachmentID -1);
-			mAttachmentPoints[attachmentID] = attachment;
+        LLViewerJointAttachment* attachment = NULL;
+        bool newly_created = false;
+        if (mAttachmentPoints.find(attachmentID) == mAttachmentPoints.end())
+        {
+            attachment = new LLViewerJointAttachment();
+            newly_created = true;
+        }
+        else
+        {
+            attachment = mAttachmentPoints[attachmentID];
+        }
 
-			// now add attachment joint
-			parent_joint->addChild(attachment);
-		}
-	}
+        attachment->setName(info->mName);
+        LLJoint *parent_joint = getJoint(info->mJointName);
+        if (!parent_joint)
+        {
+            // If the intended parent for attachment point is unavailable, avatar_lad.xml is corrupt.
+            LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL;
+            LL_ERRS() << "Invalid avatar_lad.xml file" << LL_ENDL;
+        }
 
-	return TRUE;
+        if (info->mHasPosition)
+        {
+            attachment->setOriginalPosition(info->mPosition);
+            attachment->setDefaultPosition(info->mPosition);
+        }
+			
+        if (info->mHasRotation)
+        {
+            LLQuaternion rotation;
+            rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD,
+                             info->mRotationEuler.mV[VY] * DEG_TO_RAD,
+                             info->mRotationEuler.mV[VZ] * DEG_TO_RAD);
+            attachment->setRotation(rotation);
+        }
+
+        int group = info->mGroup;
+        if (group >= 0)
+        {
+            if (group < 0 || group > 9)
+            {
+                LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL;
+            }
+            else
+            {
+                attachment->setGroup(group);
+            }
+        }
+
+        attachment->setPieSlice(info->mPieMenuSlice);
+        attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson);
+        attachment->setIsHUDAttachment(info->mIsHUDAttachment);
+        // attachment can potentially be animated, needs a number.
+        attachment->setJointNum(mSkeleton.size() + attachmentID - 1);
+
+        if (newly_created)
+        {
+            mAttachmentPoints[attachmentID] = attachment;
+            
+            // now add attachment joint
+            parent_joint->addChild(attachment);
+        }
+    }
 }
 
 //-----------------------------------------------------------------------------
@@ -7679,17 +7704,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 
 	mLastAppearanceMessageTimer.reset();
 
-	ESex old_sex = getSex();
-
-	LLAppearanceMessageContents contents;
-	parseAppearanceMessage(mesgsys, contents);
+	LLPointer<LLAppearanceMessageContents> contents(new LLAppearanceMessageContents);
+	parseAppearanceMessage(mesgsys, *contents);
 	if (enable_verbose_dumps)
 	{
-		dumpAppearanceMsgParams(dump_prefix + "appearance_msg", contents);
+		dumpAppearanceMsgParams(dump_prefix + "appearance_msg", *contents);
 	}
 
 	S32 appearance_version;
-	if (!resolve_appearance_version(contents, appearance_version))
+	if (!resolve_appearance_version(*contents, appearance_version))
 	{
 		LL_WARNS() << "bad appearance version info, discarding" << LL_ENDL;
 		return;
@@ -7701,7 +7724,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 		return;
 	}
 
-	S32 this_update_cof_version = contents.mCOFVersion;
+	S32 this_update_cof_version = contents->mCOFVersion;
 	S32 last_update_request_cof_version = mLastUpdateRequestCOFVersion;
 
 	if( isSelf() )
@@ -7740,7 +7763,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 	}
 
 	// SUNSHINE CLEANUP - is this case OK now?
-	S32 num_params = contents.mParamWeights.size();
+	S32 num_params = contents->mParamWeights.size();
 	if (num_params <= 1)
 	{
 		// In this case, we have no reliable basis for knowing
@@ -7759,7 +7782,16 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 	// assumes that cof version is only updated with server-bake
 	// appearance messages.
 	mLastUpdateReceivedCOFVersion = this_update_cof_version;
-		
+    mLastProcessedAppearance = contents;
+
+    applyParsedAppearanceMessage(*contents);
+}
+
+void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& contents)
+{
+	S32 num_params = contents.mParamWeights.size();
+	ESex old_sex = getSex();
+
 	applyParsedTEMessage(contents.mTEContents);
 
 	// prevent the overwriting of valid baked textures with invalid baked textures
@@ -7900,7 +7932,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 	}
 
 	updateMeshTextures();
-	//if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");
 }
 
 // static
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 0a3965a597beaf5be500022910843d33c6676f0d..91de5c421797625d8fa37cffb3d0aef7050c92f2 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -368,7 +368,9 @@ class LLVOAvatar :
 	void				postPelvisSetRecalc( void );
 
 	/*virtual*/ BOOL	loadSkeletonNode();
+    void                initAttachmentPoints(bool ignore_hud_joints = false);
 	/*virtual*/ void	buildCharacter();
+    void                resetVisualParams();
     void				resetSkeleton();
 
 	LLVector3			mCurRootToHeadOffset;
@@ -672,9 +674,12 @@ class LLVOAvatar :
  **                    APPEARANCE
  **/
 
+    LLPointer<LLAppearanceMessageContents> 	mLastProcessedAppearance;
+    
 public:
 	void 			parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg);
 	void 			processAvatarAppearance(LLMessageSystem* mesgsys);
+    void            applyParsedAppearanceMessage(LLAppearanceMessageContents& contents);
 	void 			hideSkirt();
 	void			startAppearanceAnimation();