Index: data/runes.lua
==================================================================
--- data/runes.lua
+++ data/runes.lua
@@ -1160,10 +1160,11 @@
 							table.insert(ary, a)
 							return true
 						end
 						return false
 					end
+					local daytime = minetest.get_natural_light(ctr:offset(0,1,0)) > 9
 					for name,tree in pairs(sorcery.data.trees) do
 						try(materials.corners, tree.node)
 						try(materials.walls, tree.plank)
 						try(materials.floor, tree.plank)
 					end
@@ -1198,15 +1199,15 @@
 					if math.random(1,10) == 7 then
 					try(materials.corners, 'default:obsidianbrick')
 					end
 
 					try(materials.lamp_wall, 'default:torch_wall')
-					try(materials.lamp_wall, 'morelights_modern:wall_lamp')
+					try(materials.lamp_wall, 'morelights_modern:walllamp')
 
-					try(materials.lamp_ext, 'default:torch')
-					try(materials.lamp_ext, 'morelights_modern:wall_lamp')
-					try(materials.lamp_ext, 'morelights_modern:lantern_f')
+					try(materials.lamp_ext, 'default:torch_wall')
+					try(materials.lamp_ext, 'morelights_modern:walllamp')
+					try(materials.lamp_ext, 'morelights_vintage:lantern_w')
 
 					for _, l in pairs {
 						'default:meselamp';
 						'morelights_modern:barlight_s';
 						'morelights_modern:ceilinglight';
@@ -1334,10 +1335,18 @@
 						end
 						i=i+1
 					end
 					local t_built = per*i
 					local lighting = math.random(1,2)
+					local put_align = function(where,node,dir)
+						local dfn = function() return 0 end
+						local pt2 = minetest.registered_nodes[node].paramtype2
+						if pt2 == 'facedir' or pt2 == 'wallmounted' then
+							dfn = minetest['dir_to_' .. pt2]
+						end
+						minetest.set_node(where, { name=node, param2=dfn(dir) })
+					end
 					if lighting == 1 then
 						local lh = math.ceil(dim.y * .6)
 						local wlamps = {
 							ctr:offset(  dim.rx - 1 , lh,0);
 							ctr:offset(-(dim.rx - 1), lh,0);
@@ -1349,14 +1358,11 @@
 							i = i + 10
 							timeline[{whence=0, secs = per*i}] = function(s)
 								spark(s,where)
 								local node = select(2,sorcery.lib.tbl.pick(materials.lamp_wall))
 								minetest.sound_play('sorcery_put',{pos=where,gain=0.8},true)
-								minetest.set_node(where, {
-									name=node;
-									param2=minetest.dir_to_wallmounted(vector.normalize(ctr:offset(0,lh,0) - where)*-1);
-								})
+								put_align(where, node, vector.normalize(ctr:offset(0,lh,0) - where)*-1)
 							end
 						end i=i+1
 					elseif lighting == 2 then
 						local which = math.random(1,3)
 						if which == 1 or which == 2 then
@@ -1390,24 +1396,23 @@
 								end
 								i = i + 7
 							end
 						end
 					end
-					-- install door
+
+					-- cut out door
 					local doorside = ({
 						vector.new( dim.rx,1,0);
 						vector.new(0,1, dim.rz);
 						vector.new(-dim.rx,1,0);
 						vector.new(0,1,-dim.rz);
 					})[math.random(1,4)]
+					local doorslideaxis = doorside.z ~= 0 and 'x' or 'z'
 					local doorpos
 					if math.random(1,3) == 1 then
-						if doorside.z ~= 0 then
-							doorside.x = doorside.x + math.random(-(dim.rx-1), dim.rx-1)
-						elseif doorside.x ~= 0 then
-							doorside.z = doorside.z + math.random(-(dim.rz-1), dim.rz-1)
-						end
+						local d = dim['r'..doorslideaxis] - 1
+						doorside[doorslideaxis] = doorside[doorslideaxis] + math.random(-d,d)
 					end
 					doorpos = ctr + doorside
 					local door = mpick'door'
 					i=i+5
 					timeline[{whence=0,secs=per*i}] = function(s)
@@ -1422,10 +1427,50 @@
 -- 							type = 'node';
 -- 							above = doorpos;
 -- 							under = doorpos:offset(0,-1,0);
 -- 						})
 					end
+
+					-- install outdoor lighting
+					if math.random(1,7) == 1 or not daytime then
+						local xwall,xspc = dim.rx, dim.rx+1
+						local zwall,zspc = dim.rz, dim.rz+1
+						local lh = dim.y - 1
+						for _, o in pairs(sorcery.lib.node.offsets.corners) do
+							local w = ctr:add {
+								z = dim.rz * o.z;
+								x = dim.rx * o.x;
+								y = lh;
+							}
+							local put = function(ofs)
+								timeline[{whence=0,secs=per*i}] = function(s)
+									local p = vector.add(w,ofs)
+									if not sorcery.lib.node.is_clear(p) then return end
+									spark(s, p)
+									minetest.sound_play('sorcery_put', {pos = p, gain = 0.4}, true)
+									local lamp = mpick 'lamp_ext'
+									print('installing lamp',lamp,p,vector.new(ofs))
+									put_align(p, lamp, vector.multiply(ofs,-1))
+								end
+								i=i+1
+							end
+							put{x=o.x, y=0, z=0}
+							put{x=0,   y=0, z=o.z}
+						end
+					end
+
+					-- lay down bed
+					i=i+3
+					timeline[{whence=0,secs=per*i}] = function(s)
+						local bed = 'beds:bed'
+						if math.random(1,3) == 1 then bed = 'beds:fancy_bed' end
+						local top = ctr:offset(dim.rx-1,1,dim.rz-1)
+						sorcery.lib.node.install_bed(bed, top, vector.new(1,0,0))
+						spark(s, top)
+						spark(s, top:offset(-1,0,0))
+						minetest.sound_play('sorcery_put', {pos = doorpos, gain = 0.9}, true)
+					end
 
 					sorcery.spell.cast {
 						name = 'sorcery:shelter';
 						groups = {'genesis','construct'};
 						caster = ctx.caster;

Index: lib/node.lua
==================================================================
--- lib/node.lua
+++ lib/node.lua
@@ -6,10 +6,16 @@
 		{x =  1, y =  0, z =  0};
 		{x = -1, y =  0, z =  0};
 		{x =  0, y =  0, z =  1};
 		{x =  0, y =  0, z = -1};
 	};
+	corners = {
+		{x =  1, y =  0, z =  1};
+		{x = -1, y =  0, z =  1};
+		{x = -1, y =  0, z = -1};
+		{x =  1, y =  0, z = -1};
+	};
 	planecorners = {
 		{x =  1, y =  0, z =  1};
 		{x = -1, y =  0, z =  1};
 		{x = -1, y =  0, z = -1};
 		{x =  1, y =  0, z = -1};
@@ -115,33 +121,35 @@
 		i = i + 1
 	until i > #stack
 	return nodes, positions
 end;
 
+local is_air = function(pos)
+	local n = force(pos)
+	if n.name == 'air' then return true end
+	local d = minetest.registered_nodes[n.name]
+	if not d then return false end
+	return (d.walkable == false) and (d.drawtype == 'airlike' or d.buildable_to == true)
+end;
+
+local is_clear = function(pos)
+	if not sorcery.lib.node.is_air(pos) then return false end
+	local ents = minetest.get_objects_inside_radius(pos,0.5)
+	if #ents > 0 then return false end
+	return true
+end;
 return {
 	offsets = ofs;
 	purge_container = function(...) return purge_container(nil, ...) end;
 	purge_only = function(lst)
 		return function(...)
 			return purge_container(lst, ...)
 		end
 	end; 
 
-	is_air = function(pos)
-		local n = force(pos)
-		if n.name == 'air' then return true end
-		local d = minetest.registered_nodes[n.name]
-		if not d then return false end
-		return (d.walkable == false) and (d.drawtype == 'airlike' or d.buildable_to == true)
-	end;
-
-	is_clear = function(pos)
-		if not sorcery.lib.node.is_air(pos) then return false end
-		local ents = minetest.get_objects_inside_radius(pos,0.5)
-		if #ents > 0 then return false end
-		return true
-	end;
+	is_air = is_air;
+	is_clear = is_clear;
 
 	insert = function(item, slot, npos, user, inv)
 		inv = inv or minetest.get_meta(npos):get_inventory()
 		if inv:room_for_item(slot,item) then
 			inv:add_item(slot,item)
@@ -154,10 +162,26 @@
 				end
 			end
 			minetest.add_item(npos, item)
 		until true end
 	end;
+
+	install_bed = function(bed, where, dir)
+		local bottom = bed .. '_bottom'
+		local top = bed .. '_top'
+		local d
+		if type(dir) == 'number' then
+			d = dir
+			dir = minetest.facedir_to_dir(d)
+		else
+			d = minetest.dir_to_facedir(dir)
+		end
+		if not is_clear(where) and is_clear(where - dir) then return false end
+		minetest.set_node(where,       {name = top, param2 = d})
+		minetest.set_node(where - dir, {name = bottom, param2 = d})
+		return true
+	end;
 
 	tree_is_live = function(pos, checklight) -- VERY EXPENSIVE FUNCTION
 		-- this is going to require some explanation.
 		--
 		-- for various purposes, we want to be able to tell the difference between
@@ -213,11 +237,12 @@
 		-- meta keys for me to consider it an option.
 		--
 		-- verdict: not very good, but decent enough for most cases. mtg should have
 		--          done better than this, but now we're all stuck with their bullshit
 		--
-		--  UPDATE: in pratice this is way too expensive to be functional, and causes servers to hang. we're replacing it with a simpler version
+		--  UPDATE: in practice this was way too expensive to be functional, and causes
+		--          servers to hang. ripped it out and replaced it with a simpler version
 
 		local treetype = force(pos).name
 		if minetest.get_item_group(treetype, 'tree') == 0 then -- sir this is not a tree
 			return nil -- 無
 		end

Index: recipes.lua
==================================================================
--- recipes.lua
+++ recipes.lua
@@ -489,11 +489,11 @@
 },1,{
 	{'basic_materials:silver_wire', 'basic_materials:empty_spool'};
 	{'basic_materials:silver_wire', 'basic_materials:empty_spool'};
 	{'basic_materials:silver_wire', 'basic_materials:empty_spool'};
 })
-
+regtech('axial_dispulsor', 'Axial Dispulsor',{metal=1})
 regtech('conduction_plate', 'Conduction Plate', {metal = 1}, {
 	{'','sorcery:disc_copper',''};
 	{'','stairs:slab_stone',''};
 	{'basic_materials:copper_wire','basic_materials:steel_bar','basic_materials:copper_wire'};
 }, 1, {