diff --git a/bonemeal.lua b/bonemeal.lua
index 07f6ec18d173453c93267fa9538daa7c56c7743c..34d244f9818ca8f1e5bdb198aa02f83097f00523 100644
--- a/bonemeal.lua
+++ b/bonemeal.lua
@@ -20,6 +20,11 @@ minetest.register_craft({
 	recipe = {'bones:bones'},
 })
 
+minetest.register_craft( {
+	type = "shapeless",
+	output = "dye:white 2",
+	recipe = {"ethereal:bonemeal"},
+})
 
 -- add bones to dirt
 minetest.override_item("default:dirt", {
diff --git a/dirt.lua b/dirt.lua
index c14f6a4c5625f27ad364aa965463de2379a53258..483feb68887e3f96d44ad7f24ed16157fa604cf6 100644
--- a/dirt.lua
+++ b/dirt.lua
@@ -74,85 +74,259 @@ dirts = {
 	"ethereal:bamboo_dirt", "ethereal:jungle_dirt", "ethereal:grove_dirt",
 	"ethereal:prairie_dirt", "ethereal:cold_dirt", "ethereal:crystal_dirt",
 	"ethereal:mushroom_dirt", "ethereal:fiery_dirt", "ethereal:gray_dirt",
-	"default:dirt_with_dry_grass"
+	"default:dirt_with_grass", "default:dirt_with_dry_grass", "ethereal:green_dirt",
+	"default:dirt_with_snow", "default:dirt_with_dry_grass"
 }
 
 -- check surrounding grass and change dirt to same colour
-minetest.register_abm({
-	nodenames = {"default:dirt_with_grass", "default:dirt"},
-	neighbors = {"air"},
-	interval = 6,
-	chance = 65,
-	catch_up = false,
+local grass_spread = function(pos, node)
 
-	action = function(pos, node)
+	-- not enough light
+	local above = {x = pos.x, y = pos.y + 1, z = pos.z}
 
-		-- not enough light
-		local above = {x = pos.x, y = pos.y + 1, z = pos.z}
+	if (minetest.get_node_light(above) or 0) < 13 then
+		return
+	end
 
-		if (minetest.get_node_light(above) or 0) < 13 then
-			return
+	-- water above grass
+	local name = minetest.get_node(above).name
+	local def = minetest.registered_nodes[name]
+
+	if name == "ignore" or not def or def.liquidtype ~= "none" then
+		return
+	end
+
+	local curr_max, curr_type, num  = 0, ""
+
+	-- find all default and ethereal grasses in area around dirt
+	local positions, grasses = minetest.find_nodes_in_area(
+		{x = pos.x - 1, y = pos.y - 2, z = pos.z - 1},
+		{x = pos.x + 1, y = pos.y + 2, z = pos.z + 1},
+		{"group:ethereal_grass", "default:dirt_with_grass",
+		"default:dirt_with_dry_grass", "default:dirt_with_snow"})
+
+	-- count new grass nodes
+	for n = 1, #dirts do
+
+		num = grasses[ dirts[n] ] or 0
+
+		if num > curr_max then
+			curr_max = num
+			curr_type = dirts[n]
 		end
+	end
 
-		-- water above grass
-		local name = minetest.get_node(above).name
-		local nodef = minetest.registered_nodes[name]
+	-- no grass nearby, keep as dirt
+	if curr_type == "" then
+		return
+	end
 
-		if name == "ignore" or not nodef or nodef.liquidtype ~= "none" then
-			return
+	-- change default green grass to ethereal green grass
+	if curr_type == "default:dirt_with_grass" then
+		curr_type = "ethereal:green_dirt"
+	end
+
+	minetest.swap_node(pos, {name = curr_type})
+end
+
+-- any grass with a block above will turn into dirt
+local grass_devoid = function(pos, node)
+
+	local above = {x = pos.x, y = pos.y + 1, z = pos.z}
+	local name = minetest.get_node(above).name
+	local nodedef = minetest.registered_nodes[name]
+
+	if name ~= "ignore" and nodedef and not ((nodedef.sunlight_propagates or
+			nodedef.paramtype == "light") and
+			nodedef.liquidtype == "none") then
+
+		minetest.swap_node(pos, {name = "default:dirt"})
+	end
+end
+
+-- flower spread, also crystal and fire flower regeneration
+local flower_spread = function(pos, node)
+
+	local light = minetest.get_node_light(pos)
+
+	if not light
+	or light < 13 then
+		return
+	end
+
+	local pos0 = {x = pos.x - 4, y = pos.y - 2, z = pos.z - 4}
+	local pos1 = {x = pos.x + 4, y = pos.y + 2, z = pos.z + 4}
+	local num = #minetest.find_nodes_in_area_under_air(pos0, pos1, "group:flora")
+
+	if num > 3
+	and node.name == "ethereal:crystalgrass" then
+
+		local grass = minetest.find_nodes_in_area_under_air(
+			pos0, pos1, {"ethereal:crystalgrass"})
+
+		if #grass > 4
+		and not minetest.find_node_near(pos, 4, {"ethereal:crystal_spike"}) then
+
+			grass = grass[math.random(#grass)]
+
+			grass.y = grass.y - 1
+
+			if minetest.get_node(grass).name == "ethereal:crystal_dirt" then
+
+				grass.y = grass.y + 1
+
+				minetest.swap_node(grass, {name = "ethereal:crystal_spike"})
+			end
 		end
 
-		local curr_max, num  = 0
-		local curr_type = "ethereal:green_dirt" -- fallback
-		local positions, grasses = minetest.find_nodes_in_area(
-			{x = (pos.x - 2), y = (pos.y - 2), z = (pos.z - 2)},
-			{x = (pos.x + 2), y = (pos.y + 2), z = (pos.z + 2)},
-			"group:ethereal_grass")
+		return
 
-		-- count new grass nodes
-		for n = 1, #dirts do
+	elseif num > 3
+	and node.name == "ethereal:dry_shrub" then
 
-			num = grasses[dirts[n]] or 0
+		local grass = minetest.find_nodes_in_area_under_air(
+			pos0, pos1, {"ethereal:dry_shrub"})
 
-			if num > curr_max then
-				curr_max = num
-				curr_type = dirts[n]
+		if #grass > 8
+		and not minetest.find_node_near(pos, 4, {"ethereal:fire_flower"}) then
+
+			grass = grass[math.random(#grass)]
+
+			grass.y = grass.y - 1
+
+			if minetest.get_node(grass).name == "ethereal:fiery_dirt" then
+
+				grass.y = grass.y + 1
+
+				minetest.swap_node(grass, {name = "ethereal:fire_flower"})
 			end
 		end
 
-		minetest.swap_node(pos, {name = curr_type})
+		return
+
+	elseif num > 3 then
+		return
 	end
-})
 
--- have dirt with dry grass spreads like ethereal grasses
-minetest.override_item("default:dirt_with_dry_grass", {
-	groups = {crumbly = 3, soil = 1, ethereal_grass = 1},
-})
+	local seedling = minetest.find_nodes_in_area_under_air(
+		pos0, pos1, {"group:soil"})
+
+	if #seedling > 0 then
+
+		seedling = seedling[math.random(#seedling)]
+		seedling.y = seedling.y + 1
+
+		light = minetest.get_node_light(seedling)
+
+		if not light
+		or light < 13 then
+			return
+		end
+
+		minetest.swap_node(seedling, {name = node.name})
+	end
+end
 
--- if grass devoid of light, change to dirt
-minetest.register_abm({
-	nodenames = {"group:ethereal_grass"},
-	interval = 8,
-	chance = 40, -- 50
-	catch_up = false,
-	action = function(pos, node)
+-- grow papyrus up to 4 high and bamboo up to 8 high
+local grow_papyrus = function(pos, node)
 
-		local name = minetest.get_node({
-			x = pos.x,
-			y = pos.y + 1,
-			z = pos.z
-		}).name
+	local oripos = pos.y
+	local high = 4
 
-		local nodedef = minetest.registered_nodes[name]
+	pos.y = pos.y - 1
 
-		if name ~= "ignore" and nodedef
-		and not ((nodedef.sunlight_propagates or nodedef.paramtype == "light")
-		and nodedef.liquidtype == "none") then
+	local nod = minetest.get_node_or_nil(pos)
 
-			minetest.swap_node(pos, {name = "default:dirt"})
+	if not nod
+	or minetest.get_item_group(nod.name, "soil") < 1
+	or minetest.find_node_near(pos, 3, {"group:water"}) == nil then
+		return
+	end
+
+	if node.name == "ethereal:bamboo" then
+		high = 8
+	end
+
+	pos.y = pos.y + 1
+
+	local height = 0
+
+	while height < high
+	and minetest.get_node(pos).name == node.name do
+		height = height + 1
+		pos.y = pos.y + 1
+	end
+
+	nod = minetest.get_node_or_nil(pos)
+
+	if nod
+	and nod.name == "air"
+	and height < high then
+
+		if node.name == "ethereal:bamboo"
+		and height == (high - 1) then
+
+			ethereal.grow_bamboo_tree({x = pos.x, y = oripos, z = pos.z})
+		else
+			minetest.swap_node(pos, {name = node.name})
 		end
 	end
-})
+
+end
+
+-- loop through active abm's
+for _, ab in pairs(minetest.registered_abms) do
+
+	local label = ab.label or ""
+	local node1 = ab.nodenames and ab.nodenames[1] or ""
+	local node2 = ab.nodenames and ab.nodenames[2] or ""
+	local neigh = ab.neighbors and ab.neighbors[1] or ""
+
+	-- find dirt to grass abm and replace with spread function
+	if label == "Grass spread"
+	or (node1 == "default:dirt"
+	and neigh == "default:dirt_with_grass") then
+
+		--ab.interval = 2
+		--ab.chance = 1
+		ab.nodenames = {"default:dirt_with_grass", "default:dirt"}
+		ab.neighbors = {"air"}
+		ab.action = grass_spread
+
+	-- find grass devoid of light to dirt abm and change to devoid function
+	elseif label == "Grass covered"
+	or (node1 == "default:dirt_with_grass"
+	and node2 == "default:dirt_with_dry_grass") then
+
+		--ab.interval = 2
+		--ab.chance = 1
+		ab.nodenames = {
+			"default:dirt_with_grass", "default:dirt_with_dry_grass",
+			"default:dirt_with_snow", "group:ethereal_grass"
+		}
+		ab.action = grass_devoid
+
+	-- find flower spread abm and change to spread function
+	elseif label == "Flower spread"
+	or node1 == "group:flora" then
+
+		--ab.interval = 2
+		--ab.chance = 1
+		ab.nodenames = {"group:flora"}
+		ab.neighbors = {"group:soil"}
+		ab.action = flower_spread
+
+	-- find grow papyrus abm and change to grow_papyrus function
+	elseif label == "Grow papyrus"
+	or node1 == "default:papyrus" then
+
+		--ab.interval = 2
+		--ab.chance = 1
+		ab.nodenames = {"default:papyrus", "ethereal:bamboo"}
+		ab.neighbors = {"group:soil"}
+		ab.action = grow_papyrus
+	end
+end
 
 -- If Baked Clay mod not active, make Red, Orange and Grey nodes
 if not minetest.get_modpath("bakedclay") then
diff --git a/flowers.lua b/flowers.lua
deleted file mode 100644
index 79672e6655e1eee85a91761edd920b30e302c93c..0000000000000000000000000000000000000000
--- a/flowers.lua
+++ /dev/null
@@ -1,97 +0,0 @@
-
--- Flowers spread over all types of soil
-minetest.register_abm({
-	nodenames = {"group:flora"},
-	neighbors = {"group:soil"},
-	interval = 13, --25,
-	chance = 96, --15,
-	catch_up = false,
-	action = function(pos, node)
-
-		local light = minetest.get_node_light(pos)
-
-		if not light
-		or light < 13 then
-			return
-		end
-
-		local pos0 = {x = pos.x - 4, y = pos.y - 2, z = pos.z - 4}
-		local pos1 = {x = pos.x + 4, y = pos.y + 2, z = pos.z + 4}
-		local num = #minetest.find_nodes_in_area_under_air(
-			pos0, pos1, "group:flora")
-
-		if num > 3
-		and node.name == "ethereal:crystalgrass" then
-
-			local grass = minetest.find_nodes_in_area_under_air(
-				pos0, pos1, {"ethereal:crystalgrass"})
-
-			local crystal = minetest.find_nodes_in_area_under_air(
-				pos0, pos1, {"ethereal:crystal_spike"})
-
-			if #grass > 4
-			and #crystal < 1 then
-
-				grass = grass[math.random(#grass)]
-
-				grass.y = grass.y - 1
-
-				if minetest.get_node(grass).name == "ethereal:crystal_dirt" then
-
-					grass.y = grass.y + 1
-
-					minetest.swap_node(grass, {name = "ethereal:crystal_spike"})
-				end
-			end
-
-			return
-
-		elseif num > 3
-		and node.name == "ethereal:dry_shrub" then
-
-			local grass = minetest.find_nodes_in_area_under_air(
-				pos0, pos1, {"ethereal:dry_shrub"})
-
-			local fflower = minetest.find_nodes_in_area_under_air(
-				pos0, pos1, {"ethereal:fire_flower"})
-
-			if #grass > 8
-			and #fflower < 1 then
-
-				grass = grass[math.random(#grass)]
-
-				grass.y = grass.y - 1
-
-				if minetest.get_node(grass).name == "ethereal:fiery_dirt" then
-
-					grass.y = grass.y + 1
-
-					minetest.swap_node(grass, {name = "ethereal:fire_flower"})
-				end
-			end
-
-			return
-
-		elseif num > 3 then
-			return
-		end
-
-		local seedling = minetest.find_nodes_in_area_under_air(
-			pos0, pos1, {"group:soil"})
-
-		if #seedling > 0 then
-
-			seedling = seedling[math.random(#seedling)]
-			seedling.y = seedling.y + 1
-
-			light = minetest.get_node_light(seedling)
-
-			if not light
-			or light < 13 then
-				return
-			end
-
-			minetest.swap_node(seedling, {name = node.name})
-		end
-	end,
-})
diff --git a/init.lua b/init.lua
index 907efd3ffe9d6acd44182c2760340cab82dab766..183df99a3b4e6792c5d89e0b9a2542819d4c7bfc 100644
--- a/init.lua
+++ b/init.lua
@@ -1,6 +1,6 @@
 --[[
 
-	Minetest Ethereal Mod (5th June 2016)
+	Minetest Ethereal Mod (9th August 2016)
 
 	Created by ChinChow
 
@@ -53,8 +53,6 @@ dofile(path .. "/plantlife.lua")
 dofile(path .. "/mushroom.lua")
 dofile(path .. "/onion.lua")
 dofile(path .. "/crystal.lua")
-dofile(path .. "/papyrus.lua")
-dofile(path .. "/flowers.lua")
 dofile(path .. "/water.lua")
 dofile(path .. "/dirt.lua")
 dofile(path .. "/leaves.lua")
diff --git a/onion.lua b/onion.lua
index 69eb8f5a616fbb962276cbae74b7f427f779b757..b26a61bd52c3a34ea17dbf8ed11b9dfffd4a9391 100644
--- a/onion.lua
+++ b/onion.lua
@@ -68,6 +68,7 @@ minetest.register_node("ethereal:onion_5", table.copy(crop_def))
 if not farming or not farming.mod or farming.mod ~= "redo" then
 
 minetest.register_abm({
+	label = "Ethereal grow onion",
 	nodenames = {"ethereal:onion_1", "ethereal:onion_2", "ethereal:onion_3", "ethereal:onion_4"},
 	neighbors = {"farming:soil_wet"},
 	interval = 9,
diff --git a/papyrus.lua b/papyrus.lua
deleted file mode 100644
index 0c718933cd4197b10c8cedb7ff393768e64bb4e8..0000000000000000000000000000000000000000
--- a/papyrus.lua
+++ /dev/null
@@ -1,61 +0,0 @@
-
--- override default papyrus to make it walkable
-minetest.override_item("default:papyrus", {walkable = true, sunlight_propagates = true})
-
--- have papyrus grow up to 4 high and bamboo grow up to 8 in height (shared abm)
-minetest.register_abm({
-	nodenames = {"default:papyrus", "ethereal:bamboo"},
-	neighbors = {"group:soil"},
-	interval = 14, --50,
-	chance = 71, --20,
-	catch_up = false,
-	action = function(pos, node)
-
-		local oripos = pos.y
-		local high = 4
-
-		pos.y = pos.y - 1
-
-		local nod = minetest.get_node_or_nil(pos)
-
-		if not nod
-		or minetest.get_item_group(nod.name, "soil") < 1
-		or minetest.find_node_near(pos, 3, {"group:water"}) == nil then
-			return
-		end
-
-		if node.name == "ethereal:bamboo" then
-			high = 8
-		end
-
-		pos.y = pos.y + 1
-
-		local height = 0
-
-		while height < high
-		and minetest.get_node(pos).name == node.name do
-			height = height + 1
-			pos.y = pos.y + 1
-		end
-
-		nod = minetest.get_node_or_nil(pos)
-
-		if nod
-		and nod.name == "air"
-		and height < high then
-
-			if node.name == "ethereal:bamboo"
-			and height == (high - 1) then
-
-				ethereal.add_tree({
-					x = pos.x,
-					y = oripos,
-					z = pos.z
-				}, 1, 1, ethereal.bambootree)
-			else
-				minetest.swap_node(pos, {name = node.name})
-			end
-		end
-
-	end,
-})
diff --git a/sapling.lua b/sapling.lua
index 2cf34b8f0f7764d8e672f8747ee41ded99e3f0b9..1a2192e5892432b171f460134d831b1c752eefd4 100644
--- a/sapling.lua
+++ b/sapling.lua
@@ -13,7 +13,7 @@ minetest.register_node("ethereal:bamboo_sprout", {
 	walkable = false,
 	groups = {
 		snappy = 3, attached_node = 1, flammable = 2,
-		dig_immediate = 3, ethereal_sapling = 1
+		dig_immediate = 3, sapling = 1
 	},
 	sounds = default.node_sound_defaults(),
 	selection_box = {
@@ -209,6 +209,7 @@ end
 
 -- Grow saplings
 minetest.register_abm({
+	label = "Ethereal grow sapling",
 	nodenames = {"group:ethereal_sapling"},
 	interval = 10,
 	chance = 50,
diff --git a/schematics/bamboo_tree.lua b/schematics/bamboo_tree.lua
index 13f06f1f25ac3855aa71998e439c44ed070275fb..da74125ee49308ea1a0a4b98376bc043db0cabeb 100644
--- a/schematics/bamboo_tree.lua
+++ b/schematics/bamboo_tree.lua
@@ -75,3 +75,8 @@ ethereal.bambootree = {
 		{ypos = 3, prob = 127},
 	},
 }
+
+minetest.override_item("default:papyrus", {
+	walkable = true,
+	sunlight_propagates = true
+})
diff --git a/sealife.lua b/sealife.lua
index 9d0a1f7009778f00335fb78d62c27c4d36013fa7..060c1ef534ebdc474b8652de6ffd4c681c1604eb 100644
--- a/sealife.lua
+++ b/sealife.lua
@@ -137,6 +137,7 @@ minetest.register_node("ethereal:sandy", {
 
 -- randomly generate coral or seaweed and have seaweed grow up to 14 high
 minetest.register_abm({
+	label = "Grow coral/seaweed",
 	nodenames = {"ethereal:sandy"},
 	neighbors = {"group:water"},
 	interval = 15,
diff --git a/strawberry.lua b/strawberry.lua
index 0147d4347c5a0c263c730c7ddaeaf128855ac730..eea150f1e3d8eade2103a8811ba96e633aaa5ad6 100644
--- a/strawberry.lua
+++ b/strawberry.lua
@@ -87,6 +87,7 @@ minetest.register_node("ethereal:strawberry_8", table.copy(crop_def))
 if not farming or not farming.mod or farming.mod ~= "redo" then
 
 minetest.register_abm({
+	label = "Ethereal grow strawberry",
 	nodenames = {
 		"ethereal:strawberry_1", "ethereal:strawberry_2", "ethereal:strawberry_3",
 		"ethereal:strawberry_4", "ethereal:strawberry_5", "ethereal:strawberry_6",
diff --git a/water.lua b/water.lua
index 8784ac8085919ef52ca791ba2fb89eff1d20ff42..c62bfeb78948389e03cf4f4bd5c069d3771fdfc9 100644
--- a/water.lua
+++ b/water.lua
@@ -44,6 +44,7 @@ minetest.register_craft({
 
 -- If Crystal Spike, Crystal Dirt, Snow near Water, change Water to Ice
 minetest.register_abm({
+	label = "Ethereal freeze water",
 	nodenames = {
 		"ethereal:crystal_spike", "default:snow", "default:snowblock",
 		"ethereal:snowbrick"
@@ -53,19 +54,19 @@ minetest.register_abm({
 	chance = 4,
 	catch_up = false,
 	action = function(pos, node)
-		local water = minetest.find_nodes_in_area_under_air(
-			{x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
-			{x = pos.x + 1, y = pos.y + 1, z = pos.z + 1},
+
+		local near = minetest.find_node_near(pos, 1,
 			{"default:water_source", "default:river_water_source"})
 
-		if water and #water > 0 then
-			minetest.swap_node(water[1], {name = "default:ice"})
+		if near then
+			minetest.swap_node(near, {name = "default:ice"})
 		end
 	end,
 })
 
 -- If Heat Source near Ice or Snow then melt
 minetest.register_abm({
+	label = "Ethereal melt snow/ice",
 	nodenames = {
 		"default:ice", "default:snowblock", "default:snow",
 		"default:dirt_with_snow", "ethereal:snowbrick", "ethereal:icebrick"
@@ -104,6 +105,7 @@ minetest.register_abm({
 
 -- If Water Source near Dry Dirt, change to normal Dirt
 minetest.register_abm({
+	label = "Ethereal wet dry dirt",
 	nodenames = {"ethereal:dry_dirt", "default:dirt_with_dry_grass"},
 	neighbors = {"group:water"},
 	interval = 15,
@@ -121,6 +123,7 @@ minetest.register_abm({
 
 -- If torch touching water then drop as item
 minetest.register_abm({
+	label = "Ethereal drop torch",
 	nodenames = {"default:torch"},
 	neighbors = {"group:water"},
 	interval = 5,