diff --git a/src/common/models/model.h b/src/common/models/model.h
index 8a95ac783..025bb2329 100644
--- a/src/common/models/model.h
+++ b/src/common/models/model.h
@@ -77,7 +77,7 @@ public:
 	virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) = 0;
 	virtual float getAspectFactor(float vscale) { return 1.f; }
 	virtual const TArray<TRS>* AttachAnimationData() { return nullptr; };
-	virtual const TArray<VSMatrix> CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>& animationData, AActor* actor) { return {}; };
+	virtual const TArray<VSMatrix> CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>& animationData, AActor* actor, int index) { return {}; };
 
 	void SetVertexBuffer(int type, IModelVertexBuffer *buffer) { mVBuf[type] = buffer; }
 	IModelVertexBuffer *GetVertexBuffer(int type) const { return mVBuf[type]; }
diff --git a/src/common/models/model_iqm.h b/src/common/models/model_iqm.h
index 29c778dd0..21f8338e9 100644
--- a/src/common/models/model_iqm.h
+++ b/src/common/models/model_iqm.h
@@ -113,7 +113,7 @@ public:
 	void BuildVertexBuffer(FModelRenderer* renderer) override;
 	void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override;
 	const TArray<TRS>* AttachAnimationData() override;
-	const TArray<VSMatrix> CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>& animationData, AActor* actor) override;
+	const TArray<VSMatrix> CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>& animationData, AActor* actor, int index) override;
 
 private:
 	void LoadGeometry();
diff --git a/src/common/models/models_iqm.cpp b/src/common/models/models_iqm.cpp
index fc4d8123b..c883dee39 100644
--- a/src/common/models/models_iqm.cpp
+++ b/src/common/models/models_iqm.cpp
@@ -510,20 +510,16 @@ const TArray<TRS>* IQMModel::AttachAnimationData()
 	return &TRSData;
 }
 
-const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>& animationData, AActor* actor)
+const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>& animationData, AActor* actor, int index)
 {
 	const TArray<TRS>& animationFrames = &animationData ? animationData : TRSData;
 
 	int numbones = Joints.Size();
 
-	if (actor->boneComponentData == nullptr)
-	{
-		auto ptr = Create<DBoneComponents>();
-		ptr->trscomponents.Resize(numbones);
-		ptr->trsmatrix.Resize(numbones);
-		actor->boneComponentData = ptr;
-		GC::WriteBarrier(actor, ptr);
-	}
+	if(actor->boneComponentData->trscomponents[index].Size() != numbones)
+		actor->boneComponentData->trscomponents[index].Resize(numbones);
+	if (actor->boneComponentData->trsmatrix[index].Size() != numbones)
+		actor->boneComponentData->trsmatrix[index].Resize(numbones);
 
 	frame1 = clamp(frame1, 0, ((int)animationFrames.Size() - 1) / numbones);
 	frame2 = clamp(frame2, 0, ((int)animationFrames.Size() - 1) / numbones);
@@ -547,23 +543,6 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double i
 		TRS from = animationFrames[offset1 + i];
 		TRS to = animationFrames[offset2 + i];
 
-		if (actor->boneManipulationData != nullptr)
-		{
-			if (i < actor->boneManipulationData->boneComponentsOld.Size())
-			{
-				from.translation += actor->boneManipulationData->boneComponentsOld[i].translation;
-				from.rotation *= actor->boneManipulationData->boneComponentsOld[i].rotation;
-				from.scaling += actor->boneManipulationData->boneComponentsOld[i].scaling;
-			}
-
-			if (i < actor->boneManipulationData->boneComponentsNew.Size())
-			{
-				to.translation += actor->boneManipulationData->boneComponentsNew[i].translation;
-				to.rotation *= actor->boneManipulationData->boneComponentsNew[i].rotation;
-				to.scaling += actor->boneManipulationData->boneComponentsNew[i].scaling;
-			}
-		}
-
 		bone.translation = from.translation * invt + to.translation * t;
 		bone.rotation = from.rotation * invt;
 		if ((bone.rotation | to.rotation * t) < 0)
@@ -576,18 +555,18 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double i
 
 		if (Joints[i].Parent >= 0 && modifiedBone[Joints[i].Parent])
 		{
-			actor->boneComponentData->trscomponents[i] = bone;
+			actor->boneComponentData->trscomponents[index][i] = bone;
 			modifiedBone[i] = true;
 		}
-		else if (actor->boneComponentData->trscomponents[i].Equals(bone))
+		else if (actor->boneComponentData->trscomponents[index][i].Equals(bone))
 		{
-			bones[i] = actor->boneComponentData->trsmatrix[i];
+			bones[i] = actor->boneComponentData->trsmatrix[index][i];
 			modifiedBone[i] = false;
 			continue;
 		}
 		else
 		{
-			actor->boneComponentData->trscomponents[i] = bone;
+			actor->boneComponentData->trscomponents[index][i] = bone;
 			modifiedBone[i] = true;
 		}
 
@@ -612,7 +591,7 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double i
 		}
 	}
 
-	actor->boneComponentData->trsmatrix = bones;
+	actor->boneComponentData->trsmatrix[index] = bones;
 
 	for (uint32_t j = 0; j < numbones; j++)
 	{
diff --git a/src/playsim/actor.h b/src/playsim/actor.h
index 68ea64d4b..b0f8a1da7 100644
--- a/src/playsim/actor.h
+++ b/src/playsim/actor.h
@@ -695,22 +695,12 @@ class DBoneComponents : public DObject
 {
 	DECLARE_CLASS(DBoneComponents, DObject);
 public:
-	TArray<TRS>			trscomponents;
-	TArray<VSMatrix>	trsmatrix;
+	TArray<TArray<TRS>>			trscomponents;
+	TArray<TArray<VSMatrix>>	trsmatrix;
 
 	DBoneComponents() = default;
 };
 
-class DBoneManipulations : public DObject
-{
-	DECLARE_CLASS(DBoneComponents, DObject);
-public:
-	TArray<TRS>			boneComponentsNew;
-	TArray<TRS>			boneComponentsOld;
-
-	DBoneManipulations() = default;
-};
-
 class DViewPosition : public DObject
 {
 	DECLARE_CLASS(DViewPosition, DObject);
@@ -1108,7 +1098,6 @@ public:
 	double			FloatSpeed;
 	TObjPtr<DActorModelData*>		modelData;
 	TObjPtr<DBoneComponents*>		boneComponentData;
-	TObjPtr<DBoneManipulations*>	boneManipulationData;
 
 // interaction info
 	FBlockNode		*BlockNode;			// links in blocks (if needed)
diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp
index af0bfb57e..5579ade20 100644
--- a/src/playsim/p_actionfunctions.cpp
+++ b/src/playsim/p_actionfunctions.cpp
@@ -5194,91 +5194,4 @@ DEFINE_ACTION_FUNCTION(AActor, GetRenderStyle)
 		if (self->RenderStyle == LegacyRenderStyles[i]) ACTION_RETURN_INT(i);
 	}
 	ACTION_RETURN_INT(-1);	// no symbolic constant exists to handle this style.
-}
-
-//==========================================================================
-//
-// A_ManipulateBone(a bunch of crap)
-//
-// This function allows manipulating a bone
-//==========================================================================
-
-enum ManipulateBoneFlags
-{
-	BM_USEEULER = 1
-};
-
-DEFINE_ACTION_FUNCTION(AActor, A_ManipulateBone)
-{
-	PARAM_ACTION_PROLOGUE(AActor);
-	PARAM_INT(modelindex);
-	PARAM_INT(boneindex);
-	PARAM_FLOAT(positionX);
-	PARAM_FLOAT(positionY);
-	PARAM_FLOAT(positionZ);
-	PARAM_FLOAT(rotationX);
-	PARAM_FLOAT(rotationY);
-	PARAM_FLOAT(rotationZ);
-	PARAM_FLOAT(rotationW);
-	PARAM_FLOAT(scaleX);
-	PARAM_FLOAT(scaleY);
-	PARAM_FLOAT(scaleZ);
-	PARAM_INT(flags);
-
-	if (self == nullptr)
-		ACTION_RETURN_BOOL(false);
-
-	AActor* mobj = ACTION_CALL_FROM_INVENTORY() ? self : stateowner;
-
-	if (mobj->boneManipulationData == nullptr)
-	{
-		auto ptr = Create<DBoneManipulations>();
-		ptr->boneComponentsNew = *new TArray<TRS>();
-		ptr->boneComponentsOld = *new TArray<TRS>();
-		mobj->boneManipulationData = ptr;
-		GC::WriteBarrier(mobj, ptr);
-	}
-
-	while(boneindex >= mobj->boneManipulationData->boneComponentsNew.Size())
-		mobj->boneManipulationData->boneComponentsNew.Push(TRS());
-	while (boneindex >= mobj->boneManipulationData->boneComponentsOld.Size())
-		mobj->boneManipulationData->boneComponentsOld.Push(TRS());
-
-	if (flags & BM_USEEULER)
-	{
-		rotationX = rotationX * 3.14159265359f / 180.0f;
-		rotationY = rotationY * 3.14159265359f / 180.0f;
-		rotationZ = rotationZ * 3.14159265359f / 180.0f;
-
-		double cr = cos(rotationX * 0.5);
-		double sr = sin(rotationX * 0.5);
-		double cp = cos(rotationZ * 0.5);
-		double sp = sin(rotationZ * 0.5);
-		double cy = cos(rotationY * 0.5);
-		double sy = sin(rotationY * 0.5);
-
-		rotationW = cr * cp * cy + sr * sp * sy;
-		rotationX = sr * cp * cy - cr * sp * sy;
-		rotationY = cr * sp * cy + sr * cp * sy;
-		rotationZ = cr * cp * sy - sr * sp * cy;
-
-		//Printf("Rotation X is: %f\n", rotationX);
-		//Printf("Rotation Y is: %f\n", rotationY);
-		//Printf("Rotation Z is: %f\n", rotationZ);
-		//Printf("Rotation W is: %f\n", rotationW);
-	}
-
-	mobj->boneManipulationData->boneComponentsOld[boneindex] = mobj->boneManipulationData->boneComponentsNew[boneindex];
-	mobj->boneManipulationData->boneComponentsNew[boneindex].translation.X = positionX;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].translation.Y = positionZ;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].translation.Z = positionY;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].rotation.X = rotationX;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].rotation.Y = rotationY;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].rotation.Z = rotationZ;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].rotation.W = rotationW;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].scaling.X = scaleX;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].scaling.Y = scaleZ;
-	mobj->boneManipulationData->boneComponentsNew[boneindex].scaling.Z = scaleY;
-
-	return 0;
-}
+}
\ No newline at end of file
diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp
index 13ec1da7e..82287ddb4 100644
--- a/src/playsim/p_mobj.cpp
+++ b/src/playsim/p_mobj.cpp
@@ -160,7 +160,6 @@ CVAR (Int, cl_bloodtype, 0, CVAR_ARCHIVE);
 
 IMPLEMENT_CLASS(DActorModelData, false, false);
 IMPLEMENT_CLASS(DBoneComponents, false, false);
-IMPLEMENT_CLASS(DBoneManipulations, false, false);
 IMPLEMENT_CLASS(AActor, false, true)
 
 IMPLEMENT_POINTERS_START(AActor)
@@ -177,7 +176,6 @@ IMPLEMENT_POINTERS_START(AActor)
 	IMPLEMENT_POINTER(ViewPos)
 	IMPLEMENT_POINTER(modelData)
 	IMPLEMENT_POINTER(boneComponentData)
-	IMPLEMENT_POINTER(boneManipulationData)
 IMPLEMENT_POINTERS_END
 
 AActor::~AActor ()
diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp
index 4f0d487e1..312f04137 100644
--- a/src/r_data/models.cpp
+++ b/src/r_data/models.cpp
@@ -356,6 +356,15 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
 
 			bool nextFrame = smfNext && modelframe != modelframenext;
 
+			if (actor->boneComponentData == nullptr)
+			{
+				auto ptr = Create<DBoneComponents>();
+				ptr->trscomponents.Resize(modelsamount);
+				ptr->trsmatrix.Resize(modelsamount);
+				actor->boneComponentData = ptr;
+				GC::WriteBarrier(actor, ptr);
+			}
+
 			if (animationid >= 0)
 			{
 				FModel* animation = Models[animationid];
@@ -363,7 +372,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
 
 				if (!(smf->flags & MDL_MODELSAREATTACHMENTS) || evaluatedSingle == false)
 				{
-					boneData = animation->CalculateBones(modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : 0.f, *animationData, actor);
+					boneData = animation->CalculateBones(modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : 0.f, *animationData, actor, i);
 					boneStartingPosition = renderer->SetupFrame(animation, 0, 0, 0, boneData, -1);
 					evaluatedSingle = true;
 				}
@@ -372,7 +381,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
 			{
 				if (!(smf->flags & MDL_MODELSAREATTACHMENTS) || evaluatedSingle == false)
 				{
-					boneData = mdl->CalculateBones(modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : 0.f, *animationData, actor);
+					boneData = mdl->CalculateBones(modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : 0.f, *animationData, actor, i);
 					boneStartingPosition = renderer->SetupFrame(mdl, 0, 0, 0, boneData, -1);
 					evaluatedSingle = true;
 				}
diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs
index b8514d792..68fc53dd6 100644
--- a/wadsrc/static/zscript/actors/actor.zs
+++ b/wadsrc/static/zscript/actors/actor.zs
@@ -1134,7 +1134,6 @@ class Actor : Thinker native
 	deprecated("2.3", "Use 'b<FlagName> = [true/false]' instead") native void A_ChangeFlag(string flagname, bool value);
 	native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE);
 	action native void A_ChangeModel(name modeldef, int modelindex = 0, string modelpath = "", name model = "", int skinindex = 0, string skinpath = "", name skin = "", int flags = 0, int generatorindex = -1, int animationindex = 0, string animationpath = "", name animation = "");
-	action native void A_ManipulateBone(int modelindex, int boneindex, float positionX = 0, float positionY = 0, float positionZ = 0, float rotationX = 0, float rotationY = 0, float rotationZ = 0, float rotationW = 0, float scaleX = 0, float scaleY = 0, float scaleZ = 0, int flags = 0);
 
 	void A_SetFriendly (bool set)
 	{
diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs
index 53dce4d78..9a32392f9 100644
--- a/wadsrc/static/zscript/constants.zs
+++ b/wadsrc/static/zscript/constants.zs
@@ -373,12 +373,6 @@ enum ChangeModelFlags
 	CMDL_USESURFACESKIN = 1 << 2,
 };
 
-// Manipulate Bone Flags
-enum ManipulateBoneFlags
-{
-	BM_USEEULER = 1
-};
-
 // Activation flags
 enum EActivationFlags
 {