diff --git a/client/ArtifactsUIController.cpp b/client/ArtifactsUIController.cpp
index 73461a58a..30374ebc2 100644
--- a/client/ArtifactsUIController.cpp
+++ b/client/ArtifactsUIController.cpp
@@ -102,7 +102,7 @@ bool ArtifactsUIController::askToDisassemble(const CGHeroInstance * hero, const
 	if(hero->tempOwner != LOCPLINT->playerID)
 		return false;
 
-	if(art->isCombined())
+	if(art->hasParts())
 	{
 		if(ArtifactUtils::isSlotBackpack(slot) && !ArtifactUtils::isBackpackFreeSlots(hero, art->artType->getConstituents().size() - 1))
 			return false;
diff --git a/docs/modders/Entities_Format/Artifact_Format.md b/docs/modders/Entities_Format/Artifact_Format.md
index 928496dc7..83b1adca2 100644
--- a/docs/modders/Entities_Format/Artifact_Format.md
+++ b/docs/modders/Entities_Format/Artifact_Format.md
@@ -67,6 +67,9 @@ In order to make functional artifact you also need:
 		"artifact2",
 		"artifact3"
 	],
+	
+	// Optional, by default is false. Set to true if components are supposed to be fused. 
+	"fusedComponents" : true,
 
 	// Creature id to use on battle field. If set, this artifact is war machine
 	"warMachine" : "some.creature" 
diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp
index 07b83dec3..f96e17f83 100644
--- a/lib/CArtHandler.cpp
+++ b/lib/CArtHandler.cpp
@@ -61,6 +61,21 @@ const std::vector<const CArtifact*> & CCombinedArtifact::getPartOf() const
 	return partOf;
 }
 
+void CCombinedArtifact::setFused(bool isFused)
+{
+	fused = isFused;
+}
+
+bool CCombinedArtifact::isFused() const
+{
+	return fused;
+}
+
+bool CCombinedArtifact::hasParts() const
+{
+	return isCombined() && !isFused();
+}
+
 bool CScrollArtifact::isScroll() const
 {
 	return static_cast<const CArtifact*>(this)->getId() == ArtifactID::SPELL_SCROLL;
@@ -203,7 +218,7 @@ bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, b
 
 	auto artCanBePutAt = [this, simpleArtCanBePutAt](const CArtifactSet * artSet, ArtifactPosition slot, bool assumeDestRemoved) -> bool
 	{
-		if(isCombined())
+		if(hasParts())
 		{
 			if(!simpleArtCanBePutAt(artSet, slot, assumeDestRemoved))
 				return false;
@@ -606,11 +621,11 @@ void CArtHandler::loadType(CArtifact * art, const JsonNode & node) const
 
 void CArtHandler::loadComponents(CArtifact * art, const JsonNode & node)
 {
-	if (!node["components"].isNull())
+	if(!node["components"].isNull())
 	{
 		for(const auto & component : node["components"].Vector())
 		{
-			VLC->identifiers()->requestIdentifier("artifact", component, [=](si32 id)
+			VLC->identifiers()->requestIdentifier("artifact", component, [this, art](int32_t id)
 			{
 				// when this code is called both combinational art as well as component are loaded
 				// so it is safe to access any of them
@@ -619,6 +634,8 @@ void CArtHandler::loadComponents(CArtifact * art, const JsonNode & node)
 			});
 		}
 	}
+	if(!node["fusedComponents"].isNull())
+		art->setFused(node["fusedComponents"].Bool());
 }
 
 void CArtHandler::makeItCreatureArt(CArtifact * a, bool onlyCreature)
diff --git a/lib/CArtHandler.h b/lib/CArtHandler.h
index e82f43147..f0bf7d8af 100644
--- a/lib/CArtHandler.h
+++ b/lib/CArtHandler.h
@@ -46,14 +46,19 @@ namespace ArtBearer
 class DLL_LINKAGE CCombinedArtifact
 {
 protected:
-	CCombinedArtifact() = default;
+	CCombinedArtifact() : fused(false) {};
 
 	std::vector<const CArtifact*> constituents; // Artifacts IDs a combined artifact consists of, or nullptr.
 	std::vector<const CArtifact*> partOf; // Reverse map of constituents - combined arts that include this art
+	bool fused;
+
 public:
 	bool isCombined() const;
 	const std::vector<const CArtifact*> & getConstituents() const;
 	const std::vector<const CArtifact*> & getPartOf() const;
+	void setFused(bool isFused);
+	bool isFused() const;
+	bool hasParts() const;
 };
 
 class DLL_LINKAGE CScrollArtifact
diff --git a/lib/CArtifactInstance.cpp b/lib/CArtifactInstance.cpp
index 6f191e46b..f65e6d95b 100644
--- a/lib/CArtifactInstance.cpp
+++ b/lib/CArtifactInstance.cpp
@@ -44,6 +44,11 @@ bool CCombinedArtifactInstance::isPart(const CArtifactInstance * supposedPart) c
 	return false;
 }
 
+bool CCombinedArtifactInstance::hasParts() const
+{
+	return !partsInfo.empty();
+}
+
 const std::vector<CCombinedArtifactInstance::PartInfo> & CCombinedArtifactInstance::getPartsInfo() const
 {
 	return partsInfo;
diff --git a/lib/CArtifactInstance.h b/lib/CArtifactInstance.h
index f679f8b44..6ff0bdbe0 100644
--- a/lib/CArtifactInstance.h
+++ b/lib/CArtifactInstance.h
@@ -38,6 +38,7 @@ public:
 	void addPart(CArtifactInstance * art, const ArtifactPosition & slot);
 	// Checks if supposed part inst is part of this combined art inst
 	bool isPart(const CArtifactInstance * supposedPart) const;
+	bool hasParts() const;
 	const std::vector<PartInfo> & getPartsInfo() const;
 	void addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap);
 
diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp
index 6ea83ab8f..f44e6411e 100644
--- a/lib/networkPacks/NetPacksLib.cpp
+++ b/lib/networkPacks/NetPacksLib.cpp
@@ -1806,6 +1806,7 @@ void AssembledArtifact::applyGs(CGameState *gs)
 	assert(hero);
 	const auto transformedArt = hero->getArt(al.slot);
 	assert(transformedArt);
+	const auto builtArt = artId.toArtifact();
 	assert(vstd::contains_if(ArtifactUtils::assemblyPossibilities(hero, transformedArt->getTypeId()), [=](const CArtifact * art)->bool
 		{
 			return art->getId() == builtArt->getId();
@@ -1832,7 +1833,7 @@ void AssembledArtifact::applyGs(CGameState *gs)
 
 	// Find a slot for combined artifact
 	al.slot = transformedArtSlot;
-	for(const auto slot : slotsInvolved)
+	for(const auto & slot : slotsInvolved)
 	{
 		if(ArtifactUtils::isSlotEquipment(transformedArtSlot))
 		{
@@ -1855,15 +1856,18 @@ void AssembledArtifact::applyGs(CGameState *gs)
 	}
 
 	// Delete parts from hero
-	for(const auto slot : slotsInvolved)
+	for(const auto & slot : slotsInvolved)
 	{
 		const auto constituentInstance = hero->getArt(slot);
 		gs->map->removeArtifactInstance(*hero, slot);
 
-		if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot)
-			combinedArt->addPart(constituentInstance, slot);
-		else
-			combinedArt->addPart(constituentInstance, ArtifactPosition::PRE_FIRST);
+		if(!combinedArt->artType->isFused())
+		{
+			if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot)
+				combinedArt->addPart(constituentInstance, slot);
+			else
+				combinedArt->addPart(constituentInstance, ArtifactPosition::PRE_FIRST);
+		}
 	}
 
 	// Put new combined artifacts
diff --git a/lib/networkPacks/PacksForClient.h b/lib/networkPacks/PacksForClient.h
index b9f678ba6..0413113dc 100644
--- a/lib/networkPacks/PacksForClient.h
+++ b/lib/networkPacks/PacksForClient.h
@@ -1108,8 +1108,8 @@ struct DLL_LINKAGE BulkMoveArtifacts : CArtifactOperationPack
 
 struct DLL_LINKAGE AssembledArtifact : CArtifactOperationPack
 {
-	ArtifactLocation al; //where assembly will be put
-	const CArtifact * builtArt;
+	ArtifactLocation al;
+	ArtifactID artId;
 
 	void applyGs(CGameState * gs) override;
 
@@ -1118,7 +1118,7 @@ struct DLL_LINKAGE AssembledArtifact : CArtifactOperationPack
 	template <typename Handler> void serialize(Handler & h)
 	{
 		h & al;
-		h & builtArt;
+		h & artId;
 	}
 };
 
diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp
index 1f9549fa0..ab933a4f8 100644
--- a/server/CGameHandler.cpp
+++ b/server/CGameHandler.cpp
@@ -2913,7 +2913,7 @@ bool CGameHandler::assembleArtifacts(ObjectInstanceID heroID, ArtifactPosition a
 
 		AssembledArtifact aa;
 		aa.al = dstLoc;
-		aa.builtArt = combinedArt;
+		aa.artId = assembleTo;
 		sendAndApply(aa);
 	}
 	else
@@ -2921,6 +2921,9 @@ bool CGameHandler::assembleArtifacts(ObjectInstanceID heroID, ArtifactPosition a
 		if(!destArtifact->isCombined())
 			COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble is not a combined artifact!");
 
+		if(!destArtifact->hasParts())
+			COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble is fused combined artifact!");
+
 		if(ArtifactUtils::isSlotBackpack(artifactSlot)
 			&& !ArtifactUtils::isBackpackFreeSlots(hero, destArtifact->artType->getConstituents().size() - 1))
 			COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble but backpack is full!");