diff --git a/machines/induction_furnace.lua b/machines/induction_furnace.lua
index 61ead22..a59506c 100644
--- a/machines/induction_furnace.lua
+++ b/machines/induction_furnace.lua
@@ -15,29 +15,65 @@
 -- along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 local S=minetest.get_translator("industrialtest")
+industrialtest.InductionFurnace=table.copy(industrialtest.ActivatedElectricMachine)
+industrialtest.internal.unpackTableInto(industrialtest.InductionFurnace,{
+	name="industrialtest:induction_furnace",
+	description=S("Induction Furnace"),
+	tiles={
+		"industrialtest_advanced_machine_block.png",
+		"industrialtest_advanced_machine_block.png",
+		"industrialtest_advanced_machine_block.png",
+		"industrialtest_advanced_machine_block.png",
+		"industrialtest_advanced_machine_block.png",
+		"industrialtest_advanced_machine_block.png^industrialtest_electric_furnace_front.png"
+	},
+	sounds="metal",
+	requiresWrench=true,
+	facedir=true,
+	storageLists={
+		"src",
+		"dst",
+		"upgrades",
+		"powerStorage"
+	},
+	powerLists={
+		{
+			list="powerStorage",
+			direction="i"
+		}
+	},
+	active={
+		tiles={
+			"industrialtest_advanced_machine_block.png",
+			"industrialtest_advanced_machine_block.png",
+			"industrialtest_advanced_machine_block.png",
+			"industrialtest_advanced_machine_block.png",
+			"industrialtest_advanced_machine_block.png",
+			"industrialtest_advanced_machine_block.png^industrialtest_electric_furnace_front_active.png"
+		}
+	},
+	capacity=industrialtest.api.mvPowerFlow*2,
+	flow=industrialtest.api.mvPowerFlow,
+	hasPowerInput=true,
+	ioConfig="iiiiii",
+	_opPower=60,
+	_efficiency=0.5
+})
 
-local inductionFurnace={}
-inductionFurnace.opPower=60
-inductionFurnace.efficiency=0.5
-
-local function calculateMaxSrcTime(pos)
+function industrialtest.InductionFurnace.onConstruct(self,pos)
 	local meta=minetest.get_meta(pos)
 	local inv=meta:get_inventory()
-	local srcList=inv:get_list("src")
-
-	local maxSrcTime=0
-	for _,slot in ipairs(srcList) do
-		local result,_=minetest.get_craft_result({
-			method="cooking",
-			width=1,
-			items={slot}
-		})
-		maxSrcTime=math.max(maxSrcTime,result.time*inductionFurnace.efficiency)
-	end
-	meta:set_float("maxSrcTime",maxSrcTime)
+	inv:set_size("src",2)
+	inv:set_size("dst",2)
+	inv:set_size("powerStorage",1)
+	inv:set_size("upgrades",4)
+	meta:set_int("heat",0)
+	meta:set_float("srcTime",0)
+	industrialtest.ActivatedElectricMachine.onConstruct(self,pos)
 end
 
-inductionFurnace.getFormspec=function(pos)
+function industrialtest.InductionFurnace.getFormspec(self,pos)
+	local parentFormspec=industrialtest.ActivatedElectricMachine.getFormspec(self,pos)
 	local meta=minetest.get_meta(pos)
 	local powerPercent=meta:get_int("industrialtest.powerAmount")/meta:get_int("industrialtest.powerCapacity")*100
 	local maxSrcTime=meta:get_float("maxSrcTime")
@@ -60,32 +96,74 @@ inductionFurnace.getFormspec=function(pos)
 		"listring[context;src]",
 		"listring[context;dst]"
     }
-	return table.concat(formspec,"")
+	return parentFormspec..table.concat(formspec,"")
 end
 
-inductionFurnace.onConstruct=function(pos,meta,inv)
-	inv:set_size("src",2)
-	inv:set_size("dst",2)
-	inv:set_size("powerStorage",1)
-	inv:set_size("upgrades",4)
-	meta:set_int("heat",0)
-	meta:set_float("srcTime",0)
-end
-
-inductionFurnace.onTimer=function(pos,elapsed,meta,inv)
-	local shouldRerunTimer=false
-	local shouldUpdateFormspec=false
+function industrialtest.InductionFurnace.update(self,pos,elapsed,meta,inv)
 	local srcList=inv:get_list("src")
 	local heat=meta:get_int("heat")
-
-	shouldRerunTimer,shouldUpdateFormspec=industrialtest.internal.chargeFromPowerStorageItem(meta,inv)
+	local shouldRerunTimer=false
+	local shouldUpdateFormspec=false
 
 	if heat>0 then
 		meta:set_int("heat",math.max(heat-math.max(2*elapsed,1),0))
-		shouldRerunTimer=shouldRerunTimer or heat>0
+		shouldRerunTimer=true
 		shouldUpdateFormspec=true
 	end
 
+	return shouldRerunTimer,shouldUpdateFormspec
+end
+
+function industrialtest.InductionFurnace.allowMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count)
+	if toList=="dst" then
+		return 0
+	end
+	return industrialtest.ActivatedElectricMachine.allowMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count)
+end
+
+function industrialtest.InductionFurnace.allowMetadataInventoryPut(self,pos,listname,index,stack)
+	if listname=="dst" then
+		return 0
+	end
+	return industrialtest.ActivatedElectricMachine.allowMetadataInventoryPut(self,pos,listname,index,stack)
+end
+
+function industrialtest.InductionFurnace.onMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count)
+	industrialtest.ActivatedElectricMachine.onMetadataInventoryMove(self,pos,fromList,fromIndex,toList,toIndex,count)
+	if fromList=="src" or toList=="src" then
+		self:calculateMaxSrcTime(pos)
+	end
+	if fromList=="src" and self.isInputEmpty(pos) then
+		local meta=minetest.get_meta(pos)
+		meta:set_float("srcTime",-1)
+		meta:set_float("maxSrcTime",0)
+		self:updateFormspec(pos)
+	elseif toList=="src" or (fromList=="dst" and not self.isOutputFull(pos)) then
+		self:triggerIfNeeded(pos)
+	end
+end
+
+function industrialtest.InductionFurnace.onMetadataInventoryPut(self,pos,listname,index,stack,player)
+	industrialtest.ActivatedElectricMachine.onMetadataInventoryPut(self,pos,listname,index,stack,player)
+	if listname=="src" then
+		self:calculateMaxSrcTime(pos)
+		self:triggerIfNeeded(pos)
+	end
+end
+
+function industrialtest.InductionFurnace.onMetadataInventoryTake(self,pos,listname,index,stack)
+	if listname=="src" then
+		self:calculateMaxSrcTime(pos)
+	elseif listname=="dst" and not self.isOutputFull(pos) then
+		self:triggerIfNeeded(pos)
+	end
+end
+
+function industrialtest.InductionFurnace.shouldActivate(self,pos)
+	local meta=minetest.get_meta(pos)
+	local inv=meta:get_inventory()
+	local srcList=inv:get_list("src")
+
 	for _,slot in ipairs(srcList) do
 		if not slot:is_empty() then
 			local result,after=minetest.get_craft_result({
@@ -94,68 +172,27 @@ inductionFurnace.onTimer=function(pos,elapsed,meta,inv)
 				items={slot}
 			})
 			if result.time>0 and inv:room_for_item("dst",result.item) then
-				minetest.swap_node(pos,{
-					name="industrialtest:induction_furnace_active",
-					param2=minetest.get_node(pos).param2
-				})
-				minetest.get_node_timer(pos):start(industrialtest.updateDelay)
-				return false,shouldUpdateFormspec
+				return meta:get_int("industrialtest.powerAmount")>=self._opPower
 			end
 		end
 	end
 
-	return shouldRerunTimer,shouldUpdateFormspec
+	return false
 end
 
-inductionFurnace.allowMetadataInventoryMove=function(pos,fromList,fromIndex,toList,toIndex,count)
-	if toList=="dst" then
-		return 0
-	end
-	return count
+function industrialtest.InductionFurnace.shouldDeactivate(self,pos)
+	return not self:shouldActivate(pos)
 end
 
-inductionFurnace.allowMetadataInventoryPut=function(pos,listname,index,stack)
-	if listname=="dst" then
-		return 0
-	end
-	return stack:get_count()
-end
-
-inductionFurnace.onMetadataInventoryPut=function(pos,listname)
-	if listname=="src" then
-		calculateMaxSrcTime(pos)
-	end
-	minetest.get_node_timer(pos):start(industrialtest.updateDelay)
-end
-
-inductionFurnace.onMetadataInventoryMove=function(pos,fromList,fromIndex,toList)
-	if fromList=="src" or toList=="src" then
-		calculateMaxSrcTime(pos)
-	end
-	minetest.get_node_timer(pos):start(industrialtest.updateDelay)
-end
-
-inductionFurnace.onMetadataInventoryTake=function(pos,listname)
-	if listname=="src" then
-		calculateMaxSrcTime(pos)
-	end
-	if listname=="dst" then
-		minetest.get_node_timer(pos):start(industrialtest.updateDelay)
-	end
-end
-
-inductionFurnace.activeOnTimer=function(pos,elapsed,meta,inv)
+function industrialtest.InductionFurnace.activeUpdate(self,pos,elapsed,meta,inv)
 	local srcList=inv:get_list("src")
 	local powerAmount=meta:get_int("industrialtest.powerAmount")
 	local srcTime=meta:get_float("srcTime")
 	local maxSrcTime=meta:get_float("maxSrcTime")
 	local heat=meta:get_int("heat")
 	local speed=industrialtest.api.getMachineSpeed(meta)
-	local requiredPower=elapsed*inductionFurnace.opPower*speed
+	local requiredPower=elapsed*self._opPower*speed
 
-	industrialtest.internal.chargeFromPowerStorageItem(meta,inv)
-
-	local shouldContinue=false
 	local results={}
 	for _,slot in ipairs(srcList) do
 		if slot:is_empty() then
@@ -168,23 +205,13 @@ inductionFurnace.activeOnTimer=function(pos,elapsed,meta,inv)
 			})
 			if result.time>0 and inv:room_for_item("dst",result.item) then
 				table.insert(results,result.item)
-				shouldContinue=true
 			else
 				table.insert(results,false)
 			end
 		end
 	end
-	if not shouldContinue or powerAmount<requiredPower then
-		meta:set_float("srcTime",0)
-		minetest.swap_node(pos,{
-			name="industrialtest:induction_furnace",
-			param2=minetest.get_node(pos).param2
-		})
-		minetest.get_node_timer(pos):start(industrialtest.updateDelay)
-		return false,true
-	end
 
-	srcTime=srcTime+elapsed*(1+heat/100)
+	srcTime=srcTime+elapsed*(1+heat/200)
 	if srcTime>=maxSrcTime then
 		for i,result in ipairs(results) do
 			if result then
@@ -206,55 +233,56 @@ inductionFurnace.activeOnTimer=function(pos,elapsed,meta,inv)
 
 	industrialtest.api.addPower(meta,-requiredPower)
 
-	return true,true
+	return true
 end
 
-industrialtest.internal.registerMachine({
-	name="induction_furnace",
-	displayName=S("Induction Furnace"),
-	capacity=industrialtest.api.mvPowerFlow*2,
-	getFormspec=inductionFurnace.getFormspec,
-	flow=industrialtest.api.mvPowerFlow,
-	ioConfig="iiiiii",
-	requiresWrench=true,
-	registerActiveVariant=true,
-	sounds="metal",
-	powerSlots={"powerStorage"},
-	storageSlots={"src","dst","powerStorage","upgrades"},
-	groups={
-		_industrialtest_hasPowerInput=1
-	},
-	customKeys={
-		tiles={
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png^industrialtest_electric_furnace_front.png"
-		},
-		paramtype2="facedir",
-		legacy_facedir_simple=true
-	},
-	activeCustomKeys={
-		tiles={
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png",
-			"industrialtest_advanced_machine_block.png^industrialtest_electric_furnace_front_active.png"
-		}
-	},
-	onConstruct=inductionFurnace.onConstruct,
-	onTimer=inductionFurnace.onTimer,
-	allowMetadataInventoryMove=inductionFurnace.allowMetadataInventoryMove,
-	allowMetadataInventoryPut=inductionFurnace.allowMetadataInventoryPut,
-	onMetadataInventoryPut=inductionFurnace.onMetadataInventoryPut,
-	onMetadataInventoryMove=inductionFurnace.onMetadataInventoryMove,
-	onMetadataInventoryTake=inductionFurnace.onMetadataInventoryTake,
-	activeOnTimer=inductionFurnace.activeOnTimer
-})
+function industrialtest.InductionFurnace.calculateMaxSrcTime(self,pos)
+	local meta=minetest.get_meta(pos)
+	local inv=meta:get_inventory()
+	local srcList=inv:get_list("src")
+
+	local maxSrcTime=0
+	for _,slot in ipairs(srcList) do
+		local result,_=minetest.get_craft_result({
+			method="cooking",
+			width=1,
+			items={slot}
+		})
+		maxSrcTime=math.max(maxSrcTime,result.time*self._efficiency)
+	end
+	meta:set_float("maxSrcTime",maxSrcTime)
+end
+
+function industrialtest.InductionFurnace.isInputEmpty(pos)
+	local meta=minetest.get_meta(pos)
+	local inv=meta:get_inventory()
+	local srcList=inv:get_list("src")
+
+	for _,slot in ipairs(srcList) do
+		if not slot:is_empty() then
+			return false
+		end
+	end
+
+	return true
+end
+
+function industrialtest.InductionFurnace.isOutputFull(pos)
+	local meta=minetest.get_meta(pos)
+	local inv=meta:get_inventory()
+	local dstList=inv:get_list("dst")
+
+	for _,slot in ipairs(dstList) do
+		if slot:get_free_space()>0 then
+			return false
+		end
+	end
+
+	return true
+end
+
+industrialtest.InductionFurnace:register()
+
 minetest.register_craft({
 	type="shaped",
 	output="industrialtest:induction_furnace",