diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt
index 980d14dd2..1de9f025b 100644
--- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt
+++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt
@@ -793,6 +793,9 @@ private fun items(provider: MatteryLanguageProvider) {
 		add(MItems.PORTABLE_DENSE_CONDENSATION_DRIVE, "Portable Dense Condensation Drive")
 		add(MItems.TRITANIUM_ORE_CLUMP, "Raw Tritanium")
 		add(MItems.PATTERN_DRIVE_NORMAL, "Pattern Drive")
+		add(MItems.PATTERN_DRIVE_DOUBLE, "Double-Level Pattern Drive")
+		add(MItems.PATTERN_DRIVE_TRIPLE, "Triple-Level Pattern Drive")
+		add(MItems.PATTERN_DRIVE_QUAD, "Quad-Level Pattern Drive")
 		add(MItems.PATTERN_DRIVE_CREATIVE, "Creative Pattern Drive")
 
 		add(MItems.PATTERN_DRIVE_CREATIVE2, "Omni-Present Pattern Drive")
diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt
index 4165fc8a9..0603e4475 100644
--- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt
+++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt
@@ -794,6 +794,9 @@ private fun items(provider: MatteryLanguageProvider) {
 		add(MItems.PORTABLE_DENSE_CONDENSATION_DRIVE, "Portable Dense Condensation Drive")
 		add(MItems.TRITANIUM_ORE_CLUMP, "Рудный тритан")
 		add(MItems.PATTERN_DRIVE_NORMAL, "Диск шаблонов")
+		add(MItems.PATTERN_DRIVE_DOUBLE, "Двухуровневый диск шаблонов")
+		add(MItems.PATTERN_DRIVE_TRIPLE, "Трёхуровневый диск шаблонов")
+		add(MItems.PATTERN_DRIVE_QUAD, "Четырёхуровневый диск шаблонов")
 		add(MItems.PATTERN_DRIVE_CREATIVE, "Творческий диск шаблонов")
 
 		add(MItems.PATTERN_DRIVE_CREATIVE2, "Вездесущий диск шаблонов")
diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CookingRecipes.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CookingRecipes.kt
index c9e0e69b1..bcc21b130 100644
--- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CookingRecipes.kt
+++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CookingRecipes.kt
@@ -52,6 +52,10 @@ fun addOreSmeltingRecipes(consumer: RecipeOutput) {
 }
 
 fun addMicrowaveRecipes(provider: MatteryRecipeProvider) {
-	provider.microwave("pattern_drive_normal_erase", Ingredient.of(MItems.PATTERN_DRIVE_NORMAL), Ingredient.of(MItems.PATTERN_DRIVE_NORMAL), workTicks = 30 * 20, experience = ConstantFloat.of(0f))
+
+	for (drive in listOf(MItems.PATTERN_DRIVE_NORMAL, MItems.PATTERN_DRIVE_DOUBLE, MItems.PATTERN_DRIVE_TRIPLE, MItems.PATTERN_DRIVE_QUAD)) {
+		provider.microwave("${drive.registryName!!.path}_erase", Ingredient.of(drive), Ingredient.of(drive), workTicks = 30 * 20, experience = ConstantFloat.of(0f))
+	}
+
 }
 
diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CraftingTableRecipes.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CraftingTableRecipes.kt
index c2c4793c3..cf4492d50 100644
--- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CraftingTableRecipes.kt
+++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/recipes/CraftingTableRecipes.kt
@@ -132,6 +132,31 @@ fun addCraftingTableRecipes(consumer: RecipeOutput) {
 		.unlockedBy(MItemTags.ADVANCED_CIRCUIT)
 		.build(consumer)
 
+	MatteryRecipe(MItems.PATTERN_DRIVE_DOUBLE, category = machinesCategory)
+		.setUpgradeSource(MItems.PATTERN_DRIVE_NORMAL)
+		.addUpgradeOps(UpgradeRecipe.MergePatterns)
+		.row(MItems.PATTERN_DRIVE_NORMAL, MItemTags.ADVANCED_CIRCUIT, MItems.PATTERN_DRIVE_NORMAL)
+		.unlockedBy(MItems.PATTERN_DRIVE_NORMAL)
+		.build(consumer)
+
+	MatteryRecipe(MItems.PATTERN_DRIVE_TRIPLE, category = machinesCategory)
+		.setUpgradeSource(MItems.PATTERN_DRIVE_DOUBLE)
+		.addUpgradeOps(UpgradeRecipe.MergePatterns)
+		.rowB(MItemTags.DILITHIUM_GEMS)
+		.row(MItems.PATTERN_DRIVE_DOUBLE, MItemTags.ADVANCED_CIRCUIT, MItems.PATTERN_DRIVE_DOUBLE)
+		.rowB(MItemTags.DILITHIUM_GEMS)
+		.unlockedBy(MItems.PATTERN_DRIVE_DOUBLE)
+		.build(consumer)
+
+	MatteryRecipe(MItems.PATTERN_DRIVE_QUAD, category = machinesCategory)
+		.setUpgradeSource(MItems.PATTERN_DRIVE_TRIPLE)
+		.addUpgradeOps(UpgradeRecipe.MergePatterns)
+		.row(MItemTags.DILITHIUM_GEMS, MItemTags.REINFORCED_TRITANIUM_PLATES, MItemTags.DILITHIUM_GEMS)
+		.row(MItems.PATTERN_DRIVE_TRIPLE, MItemTags.ADVANCED_CIRCUIT, MItems.PATTERN_DRIVE_TRIPLE)
+		.row(MItemTags.DILITHIUM_GEMS, MItemTags.REINFORCED_TRITANIUM_PLATES, MItemTags.DILITHIUM_GEMS)
+		.unlockedBy(MItems.PATTERN_DRIVE_TRIPLE)
+		.build(consumer)
+
 	MatteryRecipe(MItems.MATTER_CABLE, count = 16, category = machinesCategory)
 		.row(MItemTags.TRITANIUM_PLATES, MItemTags.TRITANIUM_PLATES, MItemTags.TRITANIUM_PLATES)
 		.row(Items.REDSTONE, MItemTags.COPPER_WIRES, Items.REDSTONE)
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ItemsConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ItemsConfig.kt
index 83bf3dfd7..efe4c77ee 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ItemsConfig.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ItemsConfig.kt
@@ -47,6 +47,9 @@ object ItemsConfig : AbstractConfig("items") {
 
 	object PatternDrives {
 		val NORMAL: Int by builder.defineInRange(MNames.PATTERN_DRIVE_NORMAL, 4, 1, Int.MAX_VALUE)
+		val DOUBLE: Int by builder.defineInRange(MNames.PATTERN_DRIVE_DOUBLE, 8, 1, Int.MAX_VALUE)
+		val TRIPLE: Int by builder.defineInRange(MNames.PATTERN_DRIVE_TRIPLE, 16, 1, Int.MAX_VALUE)
+		val QUAD: Int by builder.defineInRange(MNames.PATTERN_DRIVE_QUAD, 32, 1, Int.MAX_VALUE)
 	}
 
 	init {
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/UpgradeRecipe.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/UpgradeRecipe.kt
index f73766320..d91fb4d13 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/UpgradeRecipe.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/UpgradeRecipe.kt
@@ -21,9 +21,11 @@ import net.minecraft.world.item.crafting.ShapedRecipePattern
 import net.minecraft.world.item.enchantment.ItemEnchantments
 import net.minecraft.world.level.Level
 import ru.dbotthepony.mc.otm.capability.MatteryCapability
+import ru.dbotthepony.mc.otm.capability.matter.PatternState
 import ru.dbotthepony.mc.otm.core.nbt.set
 import ru.dbotthepony.mc.otm.core.registryName
 import java.util.Optional
+import java.util.UUID
 
 class UpgradeRecipe(
 	group: String,
@@ -60,6 +62,9 @@ class UpgradeRecipe(
 		COPY_ENERGY_CHARGE {
 			override val codec: MapCodec<CopyEnergyCharge> = MapCodec.unit(CopyEnergyCharge)
 		},
+		MERGE_PATTERNS {
+			override val codec: MapCodec<MergePatterns> = MapCodec.unit(MergePatterns)
+		}
 		;
 
 		private val serName = name.lowercase()
@@ -155,6 +160,34 @@ class UpgradeRecipe(
 		}
 	}
 
+	object MergePatterns : Op() {
+		override val type: OpType
+			get() = OpType.MERGE_PATTERNS
+
+		override fun apply(
+			source: ItemStack,
+			container: CraftingInput,
+			registry: HolderLookup.Provider,
+			destination: ItemStack
+		) {
+			val srcPatterns = source.getCapability(MatteryCapability.PATTERN_ITEM) ?: return
+			val dstPatterns = destination.getCapability(MatteryCapability.PATTERN_ITEM) ?: return
+
+			for (pattern in srcPatterns.patterns) {
+				val findState = dstPatterns.findPattern(pattern.item)
+
+				val new: PatternState =
+					if (findState != null) {
+						PatternState(findState.id, pattern.item, (findState.researchPercent + pattern.researchPercent).coerceAtMost(1.0))
+					} else {
+						PatternState(UUID.randomUUID(), pattern.item, pattern.researchPercent)
+					}
+
+				dstPatterns.insertPattern(new, onlyUpdate = false, simulate = false)
+			}
+		}
+	}
+
 	override fun assemble(input: CraftingInput, registry: HolderLookup.Provider): ItemStack {
 		val result = super.assemble(input, registry)
 
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt
index 75e31e2f5..dc9a01d14 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MCreativeTabs.kt
@@ -190,6 +190,9 @@ private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
 		energized(MItems.ALL_BATTERIES)
 		mattery(MItems.MATTER_CAPACITORS)
 		accept(MItems.PATTERN_DRIVE_NORMAL)
+		accept(MItems.PATTERN_DRIVE_DOUBLE)
+		accept(MItems.PATTERN_DRIVE_TRIPLE)
+		accept(MItems.PATTERN_DRIVE_QUAD)
 		accept(MItems.PATTERN_DRIVE_CREATIVE)
 		accept(MItems.PATTERN_DRIVE_CREATIVE2)
 
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt
index 55800cfcd..2d71f3701 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt
@@ -499,6 +499,9 @@ object MItems {
 	)
 
 	val PATTERN_DRIVE_NORMAL: Item by registry.register(MNames.PATTERN_DRIVE_NORMAL) { PatternStorageItem(ItemsConfig.PatternDrives::NORMAL) }
+	val PATTERN_DRIVE_DOUBLE: Item by registry.register(MNames.PATTERN_DRIVE_DOUBLE) { PatternStorageItem(ItemsConfig.PatternDrives::DOUBLE) }
+	val PATTERN_DRIVE_TRIPLE: Item by registry.register(MNames.PATTERN_DRIVE_TRIPLE) { PatternStorageItem(ItemsConfig.PatternDrives::TRIPLE) }
+	val PATTERN_DRIVE_QUAD: Item by registry.register(MNames.PATTERN_DRIVE_QUAD) { PatternStorageItem(ItemsConfig.PatternDrives::QUAD) }
 	val PATTERN_DRIVE_CREATIVE: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE) { PatternStorageItem() }
 	val PATTERN_DRIVE_CREATIVE2: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE2) { CreativePatternItem() }
 
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt
index c0c769fa5..fbc24523a 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MNames.kt
@@ -128,6 +128,10 @@ object MNames {
 	const val MATTER_CAPACITOR_CREATIVE = "matter_capacitor_creative"
 
 	const val PATTERN_DRIVE_NORMAL = "pattern_drive_normal"
+	const val PATTERN_DRIVE_DOUBLE = "pattern_drive_double"
+	const val PATTERN_DRIVE_TRIPLE = "pattern_drive_triple"
+	const val PATTERN_DRIVE_QUAD = "pattern_drive_quad"
+
 	const val PATTERN_DRIVE_CREATIVE = "pattern_drive_creative"
 	const val PATTERN_DRIVE_CREATIVE2 = "pattern_drive_creative2"