diff --git a/data/brick.png b/data/brick.png
new file mode 100644
index 000000000..32d77f347
Binary files /dev/null and b/data/brick.png differ
diff --git a/data/cactus_side.png b/data/cactus_side.png
new file mode 100644
index 000000000..fc479fde6
Binary files /dev/null and b/data/cactus_side.png differ
diff --git a/data/cactus_top.png b/data/cactus_top.png
new file mode 100644
index 000000000..f9e68df51
Binary files /dev/null and b/data/cactus_top.png differ
diff --git a/data/clay.png b/data/clay.png
new file mode 100644
index 000000000..3557429d8
Binary files /dev/null and b/data/clay.png differ
diff --git a/data/clay_brick.png b/data/clay_brick.png
new file mode 100644
index 000000000..e36648e48
Binary files /dev/null and b/data/clay_brick.png differ
diff --git a/data/fence.png b/data/fence.png
new file mode 100644
index 000000000..0b99f0eb5
Binary files /dev/null and b/data/fence.png differ
diff --git a/data/lump_of_clay.png b/data/lump_of_clay.png
new file mode 100644
index 000000000..be0bab9d7
Binary files /dev/null and b/data/lump_of_clay.png differ
diff --git a/data/menulogo.png b/data/menulogo.png
index 76595c48d..cb6983e5c 100644
Binary files a/data/menulogo.png and b/data/menulogo.png differ
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 47a8d4de9..3f83c7419 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -160,8 +160,12 @@ video::ITexture * CraftItem::getImage()
 		name = "lump_of_coal.png";
 	else if(m_subname == "lump_of_iron")
 		name = "lump_of_iron.png";
+	else if(m_subname == "lump_of_clay")
+		name = "lump_of_clay.png";
 	else if(m_subname == "steel_ingot")
 		name = "steel_ingot.png";
+	else if(m_subname == "clay_brick")
+		name = "clay_brick.png";
 	else if(m_subname == "rat")
 		name = "rat.png";
 	else
@@ -199,7 +203,7 @@ u16 CraftItem::getDropCount()
 
 bool CraftItem::isCookable()
 {
-	if(m_subname == "lump_of_iron")
+	if(m_subname == "lump_of_iron" || m_subname == "lump_of_clay")
 	{
 		return true;
 	}
@@ -212,6 +216,8 @@ InventoryItem *CraftItem::createCookResult()
 	{
 		return new CraftItem("steel_ingot", 1);
 	}
+	else if(m_subname == "lump_of_clay")
+		return new CraftItem("clay_brick", 1);
 	return NULL;
 }
 
diff --git a/src/map.cpp b/src/map.cpp
index a49de3c46..ac5bd7d14 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -2045,6 +2045,20 @@ void make_tree(VoxelManipulator &vmanip, v3s16 p0)
 	}
 }
 
+void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
+{
+	MapNode cactusnode(CONTENT_CACTUS);
+
+	s16 trunk_h = 3;
+	v3s16 p1 = p0;
+	for(s16 ii=0; ii<trunk_h; ii++)
+	{
+		if(vmanip.m_area.contains(p1))
+			vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
+		p1.Y++;
+	}
+}
+
 /*
 	Noise functions. Make sure seed is mangled differently in each one.
 */
@@ -3127,6 +3141,13 @@ void makeChunk(ChunkMakeData *data)
 		if(have_sand == false)
 			continue;
 
+		// Determine whether to have clay in the sand here
+		double claynoise = noise2d_perlin(
+				0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
+				data->seed+4321, 6, 0.95);
+
+		bool have_clay = have_sand && (claynoise > 1.25);
+
 		// Find ground level
 		s16 surface_y = find_ground_level_clever(data->vmanip, p2d);
 		
@@ -3143,7 +3164,10 @@ void makeChunk(ChunkMakeData *data)
 				MapNode *n = &data->vmanip.m_data[i];
 				if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
 				{
-					n->d = CONTENT_SAND;
+					if(have_clay && (surface_y == WATER_LEVEL))
+						n->d = CONTENT_CLAY;
+					else
+						n->d = CONTENT_SAND;
 				}
 				else
 				{
@@ -3207,18 +3231,24 @@ void makeChunk(ChunkMakeData *data)
 				if(y > y_nodes_max - 6)
 					continue;
 				v3s16 p(x,y,z);
-				/*
-					Trees grow only on mud and grass
-				*/
 				{
 					u32 i = data->vmanip.m_area.index(v3s16(p));
 					MapNode *n = &data->vmanip.m_data[i];
-					if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
+					if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS && n->d != CONTENT_SAND)
 						continue;
+					// Trees grow only on mud and grass
+					if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
+					{
+						p.Y++;
+						make_tree(data->vmanip, p);
+					}
+					// Cactii grow only on sand
+					if(n->d == CONTENT_SAND)
+					{
+						p.Y++;
+						make_cactus(data->vmanip, p);
+					}
 				}
-				p.Y++;
-				// Make a tree
-				make_tree(data->vmanip, p);
 			}
 		}
 		/*u32 tree_max = relative_area / 60;
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index c006b8222..cef9bbf03 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -189,6 +189,22 @@ void init_mapnode()
 	f->is_ground_content = true;
 	f->dug_item = std::string("MaterialItem ")+itos(CONTENT_SAND)+" 1";
 	
+	i = CONTENT_CLAY;
+	f = &g_content_features[i];
+	f->setAllTextures("clay.png");
+	f->setInventoryTextureCube("clay.png", "clay.png", "clay.png");
+	f->param_type = CPT_MINERAL;
+	f->is_ground_content = true;
+	f->dug_item = std::string("CraftItem lump_of_clay 4");
+	
+	i = CONTENT_BRICK;
+	f = &g_content_features[i];
+	f->setAllTextures("brick.png");
+	f->setInventoryTextureCube("brick.png", "brick.png", "brick.png");
+	f->param_type = CPT_MINERAL;
+	f->is_ground_content = true;
+	f->dug_item = std::string("CraftItem clay_brick 4");
+	
 	i = CONTENT_TREE;
 	f = &g_content_features[i];
 	f->setAllTextures("tree.png");
@@ -215,6 +231,16 @@ void init_mapnode()
 	}
 	f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
 
+	i = CONTENT_CACTUS;
+	f = &g_content_features[i];
+	f->setAllTextures("cactus_side.png");
+	f->setTexture(0, "cactus_top.png");
+	f->setTexture(1, "cactus_top.png");
+	f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
+	f->param_type = CPT_MINERAL;
+	f->is_ground_content = true;
+	f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
+
 	i = CONTENT_GLASS;
 	f = &g_content_features[i];
 	f->light_propagates = true;
@@ -226,6 +252,7 @@ void init_mapnode()
 
 	i = CONTENT_FENCE;
 	f = &g_content_features[i];
+	f->setInventoryTexture("fence.png");
 	f->light_propagates = true;
 	f->param_type = CPT_LIGHT;
 	f->is_ground_content = true;
diff --git a/src/mapnode.h b/src/mapnode.h
index ad256585f..e8cc0ab51 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -102,6 +102,9 @@ void init_content_inventory_texture_paths();
 #define CONTENT_GLASS 20
 #define CONTENT_FENCE 21
 #define CONTENT_SANDSTONE 22
+#define CONTENT_CACTUS 23
+#define CONTENT_BRICK 24
+#define CONTENT_CLAY 25
 
 /*
 	Content feature list
diff --git a/src/materials.cpp b/src/materials.cpp
index 60c1894bf..8c23056f2 100644
--- a/src/materials.cpp
+++ b/src/materials.cpp
@@ -60,6 +60,7 @@ void initializeMaterialProperties()
 
 	setStoneLikeDiggingProperties(CONTENT_STONE, 1.0);
 	setStoneLikeDiggingProperties(CONTENT_SANDSTONE, 1.0);
+	setStoneLikeDiggingProperties(CONTENT_BRICK, 3.0);
 	setStoneLikeDiggingProperties(CONTENT_MESE, 0.5);
 	setStoneLikeDiggingProperties(CONTENT_COALSTONE, 1.5);
 	setStoneLikeDiggingProperties(CONTENT_FURNACE, 3.0);
@@ -70,9 +71,11 @@ void initializeMaterialProperties()
 	setDirtLikeDiggingProperties(CONTENT_GRASS, 1.0);
 	setDirtLikeDiggingProperties(CONTENT_GRASS_FOOTSTEPS, 1.0);
 	setDirtLikeDiggingProperties(CONTENT_SAND, 1.0);
+	setDirtLikeDiggingProperties(CONTENT_CLAY, 1.0);
 	
 	setWoodLikeDiggingProperties(CONTENT_TREE, 1.0);
 	setWoodLikeDiggingProperties(CONTENT_LEAVES, 0.15);
+	setWoodLikeDiggingProperties(CONTENT_CACTUS, 0.75);
 	setWoodLikeDiggingProperties(CONTENT_GLASS, 0.15);
 	setWoodLikeDiggingProperties(CONTENT_FENCE, 0.75);
 	setWoodLikeDiggingProperties(CONTENT_WOOD, 0.75);
diff --git a/src/server.cpp b/src/server.cpp
index c7b64f413..17850c5fa 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -3987,6 +3987,36 @@ void Server::UpdateCrafting(u16 peer_id)
 					found = true;
 				}
 			}
+
+			// Clay
+			if(!found)
+			{
+				ItemSpec specs[9];
+				specs[3] = ItemSpec(ITEM_CRAFT, "lump_of_clay");
+				specs[4] = ItemSpec(ITEM_CRAFT, "lump_of_clay");
+				specs[6] = ItemSpec(ITEM_CRAFT, "lump_of_clay");
+				specs[7] = ItemSpec(ITEM_CRAFT, "lump_of_clay");
+				if(checkItemCombination(items, specs))
+				{
+					rlist->addItem(new MaterialItem(CONTENT_CLAY, 1));
+					found = true;
+				}
+			}
+
+			// Brick
+			if(!found)
+			{
+				ItemSpec specs[9];
+				specs[3] = ItemSpec(ITEM_CRAFT, "clay_brick");
+				specs[4] = ItemSpec(ITEM_CRAFT, "clay_brick");
+				specs[6] = ItemSpec(ITEM_CRAFT, "clay_brick");
+				specs[7] = ItemSpec(ITEM_CRAFT, "clay_brick");
+				if(checkItemCombination(items, specs))
+				{
+					rlist->addItem(new MaterialItem(CONTENT_BRICK, 1));
+					found = true;
+				}
+			}
 		}
 	
 	} // if creative_mode == false
@@ -4076,8 +4106,11 @@ void setCreativeInventory(Player *player)
 		CONTENT_STONE,
 		CONTENT_SAND,
 		CONTENT_SANDSTONE,
+		CONTENT_CLAY,
+		CONTENT_BRICK,
 		CONTENT_TREE,
 		CONTENT_LEAVES,
+		CONTENT_CACTUS,
 		CONTENT_GLASS,
 		CONTENT_FENCE,
 		CONTENT_MESE,
diff --git a/src/tile.cpp b/src/tile.cpp
index 8b0c3f2ea..71e0c9638 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -507,12 +507,16 @@ void TextureSource::buildMainAtlas()
 	sourcelist.push_back("mud.png");
 	sourcelist.push_back("sand.png");
 	sourcelist.push_back("sandstone.png");
+	sourcelist.push_back("clay.png");
+	sourcelist.push_back("brick.png");
 	sourcelist.push_back("grass.png");
 	sourcelist.push_back("grass_footsteps.png");
 	sourcelist.push_back("tree.png");
 	sourcelist.push_back("tree_top.png");
 	sourcelist.push_back("water.png");
 	sourcelist.push_back("leaves.png");
+	sourcelist.push_back("cactus_side.png");
+	sourcelist.push_back("cactus_top.png");
 	sourcelist.push_back("glass.png");
 	sourcelist.push_back("mud.png^grass_side.png");
 	sourcelist.push_back("cobble.png");