From 6cc471e986c694298716c257528c653395bd757d Mon Sep 17 00:00:00 2001
From: Zefram <zefram@fysh.org>
Date: Fri, 15 Aug 2014 13:25:46 +0200
Subject: [PATCH] Simplify music player interface

---
 technic/machines/other/frames.lua |  653 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 540 insertions(+), 113 deletions(-)

diff --git a/technic/machines/other/frames.lua b/technic/machines/other/frames.lua
index df117db..427e60b 100644
--- a/technic/machines/other/frames.lua
+++ b/technic/machines/other/frames.lua
@@ -1,4 +1,11 @@
+
+local S = technic.getter
+
 frames = {}
+
+local infinite_stacks = minetest.setting_getbool("creative_mode") and minetest.get_modpath("unified_inventory") == nil
+
+local frames_pos = {}
 
 -- Helpers
 
@@ -9,35 +16,54 @@
 		local t=(-0.5-ppos.x)/pvect.x
 		local y_int=ppos.y+t*pvect.y
 		local z_int=ppos.z+t*pvect.z
-		if y_int>-0.4 and y_int<0.4 and z_int>-0.4 and z_int<0.4 then return 1 end 
+		if y_int>-0.45 and y_int<0.45 and z_int>-0.45 and z_int<0.45 then return 1 end 
 	elseif pvect.x<0 then
 		local t=(0.5-ppos.x)/pvect.x
 		local y_int=ppos.y+t*pvect.y
 		local z_int=ppos.z+t*pvect.z
-		if y_int>-0.4 and y_int<0.4 and z_int>-0.4 and z_int<0.4 then return 2 end 
+		if y_int>-0.45 and y_int<0.45 and z_int>-0.45 and z_int<0.45 then return 2 end 
 	end
 	if pvect.y>0 then
 		local t=(-0.5-ppos.y)/pvect.y
 		local x_int=ppos.x+t*pvect.x
 		local z_int=ppos.z+t*pvect.z
-		if x_int>-0.4 and x_int<0.4 and z_int>-0.4 and z_int<0.4 then return 3 end 
+		if x_int>-0.45 and x_int<0.45 and z_int>-0.45 and z_int<0.45 then return 3 end 
 	elseif pvect.y<0 then
 		local t=(0.5-ppos.y)/pvect.y
 		local x_int=ppos.x+t*pvect.x
 		local z_int=ppos.z+t*pvect.z
-		if x_int>-0.4 and x_int<0.4 and z_int>-0.4 and z_int<0.4 then return 4 end 
+		if x_int>-0.45 and x_int<0.45 and z_int>-0.45 and z_int<0.45 then return 4 end 
 	end
 	if pvect.z>0 then
 		local t=(-0.5-ppos.z)/pvect.z
 		local x_int=ppos.x+t*pvect.x
 		local y_int=ppos.y+t*pvect.y
-		if x_int>-0.4 and x_int<0.4 and y_int>-0.4 and y_int<0.4 then return 5 end 
+		if x_int>-0.45 and x_int<0.45 and y_int>-0.45 and y_int<0.45 then return 5 end 
 	elseif pvect.z<0 then
 		local t=(0.5-ppos.z)/pvect.z
 		local x_int=ppos.x+t*pvect.x
 		local y_int=ppos.y+t*pvect.y
-		if x_int>-0.4 and x_int<0.4 and y_int>-0.4 and y_int<0.4 then return 6 end 
+		if x_int>-0.45 and x_int<0.45 and y_int>-0.45 and y_int<0.45 then return 6 end 
 	end
+end
+
+local function lines(str)
+	local t = {}
+	local function helper(line) table.insert(t, line) return "" end
+	helper((str:gsub("(.-)\r?\n", helper)))
+	return t
+end
+
+local function pos_to_string(pos)
+	if pos.x == 0 then pos.x = 0 end -- Fix for signed 0
+	if pos.y == 0 then pos.y = 0 end -- Fix for signed 0
+	if pos.z == 0 then pos.z = 0 end -- Fix for signed 0
+	return tostring(pos.x).."\n"..tostring(pos.y).."\n"..tostring(pos.z)
+end
+
+local function pos_from_string(str)
+	local l = lines(str)
+	return {x = tonumber(l[1]), y = tonumber(l[2]), z = tonumber(l[3])}
 end
 
 local function pos_in_list(l,pos)
@@ -47,15 +73,22 @@
 	return false
 end
 
-local function add_table(table,toadd)
-	local i=1
-	while true do
-		o=table[i]
-		if o==toadd then return end
-		if o==nil then break end
-		i=i+1
+local function table_empty(table)
+	for _, __ in pairs(table) do
+		return false
 	end
-	table[i]=toadd
+	return true
+end
+
+local function add_table(table,toadd)
+	local i = 1
+	while true do
+		o = table[i]
+		if o == toadd then return end
+		if o == nil then break end
+		i = i+1
+	end
+	table[i] = toadd
 end
 
 local function move_nodes_vect(poslist,vect,must_not_move,owner)
@@ -69,50 +102,55 @@
 	end
 	for _,pos in ipairs(poslist) do
 		local npos=vector.add(pos,vect)
-		local name = minetest.env:get_node(npos).name
-		if (name~="air" and minetest.registered_nodes[name].liquidtype=="none") and not(pos_in_list(poslist,npos)) then
+		local name = minetest.get_node(npos).name
+		if ((name~="air" and minetest.registered_nodes[name].liquidtype=="none") or frames_pos[pos_to_string(npos)]) and not(pos_in_list(poslist,npos)) then
 			return
 		end
 		--[[if pos.x==must_not_move.x and pos.y==must_not_move.y and pos.z==must_not_move.z then
 			return
 		end]]
 	end
-	nodelist={}
-	for _,pos in ipairs(poslist) do
-		local node=minetest.env:get_node(pos)
-		local meta=minetest.env:get_meta(pos):to_table()
-		nodelist[#(nodelist)+1]={pos=pos,node=node,meta=meta}
+	local nodelist = {}
+	for _, pos in ipairs(poslist) do
+		local node = minetest.get_node(pos)
+		local meta = minetest.get_meta(pos):to_table()
+		nodelist[#(nodelist)+1] = {oldpos = pos, pos = vector.add(pos, vect), node = node, meta = meta}
 	end
-	objects={}
-	for _,pos in ipairs(poslist) do
-		for _,object in ipairs(minetest.env:get_objects_inside_radius(pos, 1)) do
-			add_table(objects,object)
+	local objects = {}
+	for _, pos in ipairs(poslist) do
+		for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
+			local entity = object:get_luaentity()
+			if not entity or not mesecon:is_mvps_unmov(entity.name) then
+				add_table(objects, object)
+			end
 		end
 	end
-	for _,obj in ipairs(objects) do
-		obj:setpos(vector.add(obj:getpos(),vect))
-		le=obj:get_luaentity()
-		if le and le.name == "pipeworks:tubed_item" then
-			le.start_pos=vector.add(le.start_pos,vect)
-		end
+	for _, obj in ipairs(objects) do
+		obj:setpos(vector.add(obj:getpos(), vect))
 	end
 	for _,n in ipairs(nodelist) do
-		local npos=vector.add(n.pos,vect)
-		minetest.env:set_node(npos,n.node)
-		local meta=minetest.env:get_meta(npos)
+		local npos = n.pos
+		minetest.set_node(npos, n.node)
+		local meta = minetest.get_meta(npos)
 		meta:from_table(n.meta)
 		for __,pos in ipairs(poslist) do
-			if npos.x==pos.x and npos.y==pos.y and npos.z==pos.z then
+			if npos.x == pos.x and npos.y == pos.y and npos.z == pos.z then
 				table.remove(poslist, __)
 				break
 			end
 		end
 	end
-	for __,pos in ipairs(poslist) do
-		minetest.env:remove_node(pos)
+	for __, pos in ipairs(poslist) do
+		minetest.remove_node(pos)
+	end
+	for _, callback in ipairs(mesecon.on_mvps_move) do
+		callback(nodelist)
 	end
 end
 
+local function is_supported_node(name)
+	return ((string.find(name, "tube") ~= nil) and (string.find(name, "pipeworks") ~= nil))
+end
 
 
 -- Frames
@@ -169,7 +207,7 @@
 	
 
 	minetest.register_node("technic:frame_"..nameext,{
-		description = "Frame",
+		description = S("Frame"),
 		tiles = {"technic_frame.png"},
 		groups=groups,
 		drawtype = "nodebox",
@@ -184,8 +222,8 @@
 		paramtype = "light",
 		frame=1,
 		drop="technic:frame_111111",
-		frame_connect_all=function(pos)
-			local nodename=minetest.env:get_node(pos).name
+		sunlight_propagates = true,
+		frame_connect_all=function(nodename)
 			l2={}
 			l1={{x=-1,y=0,z=0},{x=1,y=0,z=0},{x=0,y=-1,z=0},{x=0,y=1,z=0},{x=0,y=0,z=-1},{x=0,y=0,z=1}}
 			for i,dir in ipairs(l1) do
@@ -208,8 +246,84 @@
 				nodename=string.sub(nodename,1,-2)..newstate
 			end
 			node.name=nodename
-			minetest.env:set_node(pos,node)
-		end
+			minetest.set_node(pos,node)
+		end,
+		on_place = function(itemstack, placer, pointed_thing)
+			local pos = pointed_thing.above
+			if minetest.is_protected(pos, placer:get_player_name()) then
+				minetest.log("action", placer:get_player_name()
+					.. " tried to place " .. itemstack:get_name()
+					.. " at protected position "
+					.. minetest.pos_to_string(pos))
+				minetest.record_protection_violation(pos, placer:get_player_name())
+				return itemstack
+			end
+			if pos == nil then return end
+			local node = minetest.get_node(pos)
+			if node.name ~= "air" then
+				if is_supported_node(node.name) then
+					obj = minetest.add_entity(pos, "technic:frame_entity")
+					obj:get_luaentity():set_node({name=itemstack:get_name()})
+				end
+			else
+				minetest.set_node(pos, {name = itemstack:get_name()})
+			end
+			if not infinite_stacks then
+				itemstack:take_item()
+			end
+			return itemstack
+		end,
+		on_rightclick = function(pos, node, placer, itemstack, pointed_thing)
+			if is_supported_node(itemstack:get_name()) then
+				if minetest.is_protected(pos, placer:get_player_name()) then
+					minetest.log("action", placer:get_player_name()
+						.. " tried to place " .. itemstack:get_name()
+						.. " at protected position "
+						.. minetest.pos_to_string(pos))
+					minetest.record_protection_violation(pos, placer:get_player_name())
+					return itemstack
+				end
+				
+				minetest.set_node(pos, {name = itemstack:get_name()})
+				
+				local take_item = true
+				local def = minetest.registered_items[itemstack:get_name()]
+				-- Run callback
+				if def.after_place_node then
+					-- Copy place_to because callback can modify it
+					local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
+					if def.after_place_node(pos_copy, placer, itemstack) then
+						take_item = false
+					end
+				end
+
+				-- Run script hook
+				local _, callback
+				for _, callback in ipairs(minetest.registered_on_placenodes) do
+					-- Copy pos and node because callback can modify them
+					local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
+					local newnode_copy = {name=def.name, param1=0, param2=0}
+					local oldnode_copy = {name="air", param1=0, param2=0}
+					if callback(pos_copy, newnode_copy, placer, oldnode_copy, itemstack) then
+						take_item = false
+					end
+				end
+
+				if take_item then
+					itemstack:take_item()
+				end
+				
+				obj = minetest.add_entity(pos, "technic:frame_entity")
+				obj:get_luaentity():set_node({name=node.name})
+				
+				return itemstack
+			else
+				--local pointed_thing = {type = "node", under = pos}
+				if pointed_thing then
+					minetest.item_place_node(itemstack, placer, pointed_thing)
+				end
+			end
+		end,
 	})
 
 end
@@ -219,20 +333,190 @@
 end
 end
 
+minetest.register_entity("technic:frame_entity", {
+	initial_properties = {
+		physical = true,
+		collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
+		visual = "wielditem",
+		textures = {},
+		visual_size = {x=0.667, y=0.667},
+	},
 
+	node = {},
 
+	set_node = function(self, node)
+		self.node = node
+		local pos = self.object:getpos()
+		pos = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)}
+		frames_pos[pos_to_string(pos)] = node.name
+		local stack = ItemStack(node.name)
+		local itemtable = stack:to_table()
+		local itemname = nil
+		if itemtable then
+			itemname = stack:to_table().name
+		end
+		local item_texture = nil
+		local item_type = ""
+		if minetest.registered_items[itemname] then
+			item_texture = minetest.registered_items[itemname].inventory_image
+			item_type = minetest.registered_items[itemname].type
+		end
+		prop = {
+			is_visible = true,
+			textures = {node.name},
+		}
+		self.object:set_properties(prop)
+	end,
+
+	get_staticdata = function(self)
+		return self.node.name
+	end,
+
+	on_activate = function(self, staticdata)
+		self.object:set_armor_groups({immortal=1})
+		self:set_node({name=staticdata})
+	end,
+	
+	dig = function(self)
+		minetest.handle_node_drops(self.object:getpos(), {ItemStack("technic:frame_111111")}, self.last_puncher)
+		local pos = self.object:getpos()
+		pos = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)}
+		frames_pos[pos_to_string(pos)] = nil
+		self.object:remove()
+	end,
+	
+	on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
+		local pos = self.object:getpos()
+		if self.damage_object == nil then
+			self.damage_object = minetest.add_entity(pos, "technic:damage_entity")
+			self.damage_object:get_luaentity().remaining_time = 0.25
+			self.damage_object:get_luaentity().frame_object = self
+			self.damage_object:get_luaentity().texture_index = 0
+			self.damage_object:get_luaentity().texture_change_time = 0.15
+		else
+			self.damage_object:get_luaentity().remaining_time = 0.25
+		end
+		self.last_puncher = puncher
+		local ppos = puncher:getpos()
+		local pvect = puncher:get_look_dir()
+		local pface = get_face(pos,ppos,pvect)
+		if pface == nil then return end
+		local nodename = self.node.name
+		local newstate = tostring(1-tonumber(string.sub(nodename, -7+pface, -7+pface)))
+		if pface <= 5 then
+			nodename = string.sub(nodename, 1, -7+pface-1)..newstate..string.sub(nodename, -7+pface+1)
+		else
+			nodename = string.sub(nodename, 1, -2)..newstate
+		end
+		self.node.name = nodename
+		self:set_node(self.node)
+	end,
+	
+	on_rightclick = function(self, clicker)
+		local pos = self.object:getpos()
+		local ppos = clicker:getpos()
+		local pvect = clicker:get_look_dir()
+		local pface = get_face(pos, ppos, pvect)
+		if pface == nil then return end
+		local pos_under = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)}
+		local pos_above = {x = pos_under.x, y = pos_under.y, z = pos_under.z}
+		local index = ({"x", "y", "z"})[math.floor((pface+1)/2)]
+		pos_above[index] = pos_above[index] + 2*((pface+1)%2) - 1
+		local pointed_thing = {type = "node", under = pos_under, above = pos_above}
+		local itemstack = clicker:get_wielded_item()
+		local itemdef = minetest.registered_items[itemstack:get_name()]
+		if itemdef ~= nil then
+			itemdef.on_place(itemstack, clicker, pointed_thing)
+		end
+	end,
+})
+
+local crack = "crack_anylength.png^[verticalframe:5:0"
+minetest.register_entity("technic:damage_entity", {
+	initial_properties = {
+		visual = "cube",
+		visual_size = {x=1.01, y=1.01},
+		textures = {crack, crack, crack, crack, crack, crack},
+		collisionbox = {0, 0, 0, 0, 0, 0},
+		physical = false,
+	},
+	on_step = function(self, dtime)
+		if self.remaining_time == nil then
+			self.object:remove()
+			self.frame_object.damage_object = nil
+		end
+		self.remaining_time = self.remaining_time - dtime
+		if self.remaining_time < 0 then
+			self.object:remove()
+			self.frame_object.damage_object = nil
+		end
+		self.texture_change_time = self.texture_change_time - dtime
+		if self.texture_change_time < 0 then
+			self.texture_change_time = self.texture_change_time + 0.15
+			self.texture_index = self.texture_index + 1
+			if self.texture_index == 5 then
+				self.object:remove()
+				self.frame_object.damage_object = nil
+				self.frame_object:dig()
+			end
+			local ct = "crack_anylength.png^[verticalframe:5:"..self.texture_index
+			self.object:set_properties({textures = {ct, ct, ct, ct, ct, ct}})
+		end
+	end,
+})
+
+mesecon:register_mvps_unmov("technic:frame_entity")
+mesecon:register_mvps_unmov("technic:damage_entity")
+mesecon:register_on_mvps_move(function(moved_nodes)
+	local to_move = {}
+	for _, n in ipairs(moved_nodes) do
+		if frames_pos[pos_to_string(n.oldpos)] ~= nil then
+			to_move[#to_move+1] = {pos = n.pos, oldpos = n.oldpos, name = frames_pos[pos_to_string(n.oldpos)]}
+			frames_pos[pos_to_string(n.oldpos)] = nil
+		end
+	end
+	if #to_move > 0 then
+		for _, t in ipairs(to_move) do
+			frames_pos[pos_to_string(t.pos)] = t.name
+			local objects = minetest.get_objects_inside_radius(t.oldpos, 0.1)
+			for _, obj in ipairs(objects) do
+				local entity = obj:get_luaentity()
+				if entity and (entity.name == "technic:frame_entity" or entity.name == "technic:damage_entity") then
+					obj:setpos(t.pos)
+				end
+			end
+		end
+	end
+end)
+
+minetest.register_on_dignode(function(pos, node)
+	if frames_pos[pos_to_string(pos)] ~= nil then
+		minetest.set_node(pos, {name = frames_pos[pos_to_string(pos)]})
+		frames_pos[pos_to_string(pos)] = nil
+		local objects = minetest.get_objects_inside_radius(pos, 0.1)
+		for _, obj in ipairs(objects) do
+			local entity = obj:get_luaentity()
+			if entity and (entity.name == "technic:frame_entity" or entity.name == "technic:damage_entity") then
+				obj:remove()
+			end
+		end
+	end
+end)
 
 -- Frame motor
 local function connected(pos,c,adj)
 	for _,vect in ipairs(adj) do
 		local pos1=vector.add(pos,vect)
-		local nodename=minetest.env:get_node(pos1).name
+		local nodename=minetest.get_node(pos1).name
+		if frames_pos[pos_to_string(pos1)] then
+			nodename = frames_pos[pos_to_string(pos1)]
+		end
 		if not(pos_in_list(c,pos1)) and nodename~="air" and
 		(minetest.registered_nodes[nodename].frames_can_connect==nil or
 		minetest.registered_nodes[nodename].frames_can_connect(pos1,vect)) then
 			c[#(c)+1]=pos1
 			if minetest.registered_nodes[nodename].frame==1 then
-				local adj=minetest.registered_nodes[nodename].frame_connect_all(pos1)
+				local adj=minetest.registered_nodes[nodename].frame_connect_all(nodename)
 				connected(pos1,c,adj)
 			end
 		end
@@ -241,8 +525,11 @@
 
 local function get_connected_nodes(pos)
 	c={pos}
-	local nodename=minetest.env:get_node(pos).name
-	connected(pos,c,minetest.registered_nodes[nodename].frame_connect_all(pos))
+	local nodename=minetest.get_node(pos).name
+	if frames_pos[pos_to_string(pos)] then
+		nodename = frames_pos[pos_to_string(pos)]
+	end
+	connected(pos,c,minetest.registered_nodes[nodename].frame_connect_all(nodename))
 	return c
 end
 
@@ -251,16 +538,23 @@
 	local nnodepos = vector.add(pos, dirs[math.floor(node.param2/4)+1])
 	local dir = minetest.facedir_to_dir(node.param2)
 	local nnode=minetest.get_node(nnodepos)
+	if frames_pos[pos_to_string(nnodepos)] then
+		nnode.name = frames_pos[pos_to_string(nnodepos)]
+	end
 	local meta = minetest.get_meta(pos)
+	if meta:get_int("last_moved") == minetest.get_gametime() then
+		return
+	end
 	local owner = meta:get_string("owner")
 	if minetest.registered_nodes[nnode.name].frame==1 then
 		local connected_nodes=get_connected_nodes(nnodepos)
 		move_nodes_vect(connected_nodes,dir,pos,owner)
 	end
+	minetest.get_meta(vector.add(pos, dir)):set_int("last_moved", minetest.get_gametime())
 end
 
 minetest.register_node("technic:frame_motor",{
-	description = "Frame motor",
+	description = S("Frame Motor"),
 	tiles = {"pipeworks_filter_top.png^[transformR90", "technic_lv_cable.png", "technic_lv_cable.png",
 		"technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png"},
 	groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,mesecon=2},
@@ -280,29 +574,56 @@
 
 
 -- Templates
-local function template_connected(pos,c)
+local function template_connected(pos,c,connectors)
 	for _,vect in ipairs({{x=0,y=1,z=0},{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=-1,z=0}}) do
 		local pos1=vector.add(pos,vect)
 		local nodename=minetest.get_node(pos1).name
-		if not(pos_in_list(c,pos1)) and nodename=="technic:template" then
+		if not(pos_in_list(c,pos1)) and (nodename=="technic:template" or nodename == "technic:template_connector")then
 			local meta = minetest.get_meta(pos1)
 			if meta:get_string("connected") == "" then
 				c[#(c)+1]=pos1
-				template_connected(pos1,c)
+				template_connected(pos1,c,connectors)
+				if nodename == "technic:template_connector" then
+					connectors[#connectors+1] = pos1
+				end
 			end
 		end
 	end
 end
 
 local function get_templates(pos)
-	c={pos}
-	template_connected(pos,c)
-	return c
+	local c = {pos}
+	local connectors
+	if minetest.get_node(pos).name == "technic:template_connector" then
+		connectors = {pos}
+	else
+		connectors = {}
+	end
+	template_connected(pos,c,connectors)
+	return c, connectors
+end
+
+local function swap_template(pos, new)
+	local meta = minetest.get_meta(pos)
+	local saved_node = meta:get_string("saved_node")
+	meta:set_string("saved_node", "")
+	technic.swap_node(pos, new)
+	local meta = minetest.get_meta(pos)
+	meta:set_string("saved_node", saved_node)
 end
 
 local function save_node(pos)
 	local node = minetest.get_node(pos)
-	if node.name == "air" or node.name == "technic:template" then return end
+	if node.name == "air" then
+		minetest.set_node(pos, {name="technic:template"})
+		return
+	end
+	if node.name == "technic:template" then
+		swap_template(pos, "technic:template_connector")
+		local meta = minetest.get_meta(pos)
+		meta:set_string("connected", "")
+		return
+	end
 	local meta = minetest.get_meta(pos)
 	local meta0 = meta:to_table()
 	for _, list in pairs(meta0.inventory) do
@@ -311,6 +632,7 @@
 		end
 	end
 	node.meta = meta0
+	minetest.set_node(pos, {name="technic:template"})
 	return node
 end
 
@@ -329,82 +651,138 @@
 	local meta = minetest.get_meta(pos)
 	local c = meta:get_string("connected")
 	if c == "" then return end
-	meta:set_string("connected", "")
 	c = minetest.deserialize(c)
 	for _, vect in ipairs(c) do
-		if vect.x ~= 0 or vect.y ~= 0 or vect.z ~= 0 then
-			local pos1 = vector.add(pos, vect)
-			local saved_node = save_node(pos1)
-			minetest.set_node(pos1, {name="technic:template"})
-			local meta1 = minetest.get_meta(pos1)
-			if saved_node ~= nil then
-				meta1:set_string("saved_node", minetest.serialize(saved_node))
-			else
-				meta1:set_string("saved_node", "")
+		local pos1 = vector.add(pos, vect)
+		local saved_node = save_node(pos1)
+		local meta1 = minetest.get_meta(pos1)
+		if saved_node ~= nil then
+			meta1:set_string("saved_node", minetest.serialize(saved_node))
+		else
+			--meta1:set_string("saved_node", "")
+		end
+	end
+end
+
+local function compress_templates(pos)
+	local templates, connectors = get_templates(pos)
+	if #connectors == 0 then
+		connectors = {pos}
+	end
+	for _, cn in ipairs(connectors) do
+		local meta = minetest.get_meta(cn)
+		local c = {}
+		for _,p in ipairs(templates) do
+			local np = vector.subtract(p, cn)
+			if not pos_in_list(c,np) then
+				c[#c+1] = np
 			end
+		end
+		local cc = {}
+		for _,p in ipairs(connectors) do
+			local np = vector.subtract(p, cn)
+			if (np.x ~= 0 or np.y ~= 0 or np.z ~= 0) then
+				cc[pos_to_string(np)] = true
+			end
+		end
+		swap_template(cn, "technic:template")
+		meta:set_string("connected", minetest.serialize(c))
+		meta:set_string("connectors_connected", minetest.serialize(cc))
+	end
+	
+	for _,p in ipairs(templates) do
+		if not pos_in_list(connectors, p) then
+			minetest.set_node(p, {name = "air"})
 		end
 	end
 end
 
 local function template_drops(pos, node, oldmeta, digger)
 	local c = oldmeta.fields.connected
+	local cc = oldmeta.fields.connectors_connected
 	local drops
 	if c == "" or c == nil then
 		drops = {"technic:template 1"}
 	else
-		local stack_max = 99
-		local num = #(minetest.deserialize(c))
-		drops = {}
-		while num > stack_max do
-			drops[#drops+1] = "technic:template "..stack_max
-			num = num - stack_max
+		if cc == "" or cc == nil then
+			drops = {"technic:template 1"}
+		else
+			local dcc = minetest.deserialize(cc)
+			if not table_empty(dcc) then
+				drops = {}
+				for sp, _ in pairs(dcc) do
+					local ssp = pos_from_string(sp)
+					local p = vector.add(ssp, pos)
+					local meta = minetest.get_meta(p)
+					local d = minetest.deserialize(meta:get_string("connectors_connected"))
+					if d ~= nil then
+						d[pos_to_string({x=-ssp.x, y=-ssp.y, z=-ssp.z})] = nil
+						meta:set_string("connectors_connected", minetest.serialize(d))
+					end
+				end
+			else
+				local stack_max = 99
+				local num = #(minetest.deserialize(c))
+				drops = {}
+				while num > stack_max do
+					drops[#drops+1] = "technic:template "..stack_max
+					num = num - stack_max
+				end
+				drops[#drops+1] = "technic:template "..num
+			end
 		end
-		drops[#drops+1] = "technic:template "..num
 	end
-	print(dump(drops))
 	minetest.handle_node_drops(pos, drops, digger)
 end
 
+local function template_on_destruct(pos, node)
+	local meta = minetest.get_meta(pos)
+	local saved_node = meta:get_string("saved_node")
+	if saved_node ~= "" then
+		local nnode = minetest.deserialize(saved_node)
+		minetest.after(0, restore_node, pos, nnode)
+	end
+end
+
 minetest.register_node("technic:template",{
-	description = "Template",
+	description = S("Template"),
 	tiles = {"technic_mv_cable.png"},
 	drop = "",
 	groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
-	on_destruct = function(pos, node)
-		local meta = minetest.get_meta(pos)
-		local saved_node = meta:get_string("saved_node")
-		if saved_node ~= "" then
-			local nnode = minetest.deserialize(saved_node)
-			minetest.after(0, restore_node, pos, nnode)
-		end
-	end,
+	on_destruct = template_on_destruct,
 	after_dig_node = template_drops,
 	on_punch = function(pos,node,puncher)
-		hacky_swap_node(pos, "technic:template_disabled")
+		swap_template(pos, "technic:template_disabled")
 	end
 })
 
 minetest.register_node("technic:template_disabled",{
-	description = "Template",
+	description = S("Template"),
 	tiles = {"technic_hv_cable.png"},
 	drop = "",
-	groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
-	on_destruct = function(pos, node)
-		local meta = minetest.get_meta(pos)
-		local saved_node = meta:get_string("saved_node")
-		if saved_node ~= "" then
-			local nnode = minetest.deserialize(saved_node)
-			minetest.after(0, restore_node, pos, nnode)
-		end
-	end,
+	groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
+	on_destruct = template_on_destruct,
 	after_dig_node = template_drops,
 	on_punch = function(pos,node,puncher)
-		hacky_swap_node(pos, "technic:template")
+	local meta = minetest.get_meta(pos)
+		swap_template(pos, "technic:template_connector")
+	end
+})
+
+minetest.register_node("technic:template_connector",{
+	description = S("Template"),
+	tiles = {"technic_lv_cable.png"},
+	drop = "",
+	groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
+	on_destruct = template_on_destruct,
+	after_dig_node = template_drops,
+	on_punch = function(pos,node,puncher)
+		swap_template(pos, "technic:template")
 	end
 })
 
 minetest.register_craftitem("technic:template_replacer",{
-	description = "Template (replacing)",
+	description = S("Template (replacing)"),
 	inventory_image = "technic_template_replacer.png",
 	on_place = function(itemstack, placer, pointed_thing)
 		local p = pointed_thing.under
@@ -414,7 +792,6 @@
 		local node = minetest.get_node(p)
 		if node.name == "technic:template" then return end
 		local saved_node = save_node(p)
-		minetest.set_node(p, {name="technic:template"})
 		itemstack:take_item()
 		if saved_node ~= nil then
 			local meta = minetest.get_meta(p)
@@ -425,33 +802,23 @@
 })
 
 minetest.register_tool("technic:template_tool",{
-	description = "Template tool",
+	description = S("Template Tool"),
 	inventory_image = "technic_template_tool.png",
 	on_use = function(itemstack, puncher, pointed_thing)
 		local pos = pointed_thing.under
-		if pos == nil or (minetest.is_protected and minetest.is_protected(pos, placer:get_player_name())) then
+		if pos == nil or (minetest.is_protected and minetest.is_protected(pos, puncher:get_player_name())) then
 			return nil
 		end
 		local node = minetest.get_node(pos)
-		if node.name ~= "technic:template" then return end
+		if node.name ~= "technic:template" and node.name ~= "technic:template_connector" then return end
 		local meta = minetest.get_meta(pos)
 		local c2 = meta:get_string("connected")
 		if c2 ~= "" then
 			expand_template(pos)
-			return
+		else
+			compress_templates(pos)
 		end
-		local templates = get_templates(pos)
-		local c = {}
-		for _,p in ipairs(templates) do
-			local np = {x=p.x-pos.x, y=p.y-pos.y, z=p.z-pos.z}
-			if not pos_in_list(c,np) then
-				c[#c+1] = np
-			end
-			if p.x ~= pos.x or p.y ~= pos.y or p.z ~= pos.z then
-				minetest.set_node(p, {name = "air"})
-			end
-		end
-		meta:set_string("connected", minetest.serialize(c))
+		
 	end
 })
 
@@ -466,7 +833,7 @@
 	local c = {}
 	for _,vect in ipairs(adj) do
 		local pos1=vector.add(pos,vect)
-		local nodename=minetest.env:get_node(pos1).name
+		local nodename=minetest.get_node(pos1).name
 		if not(pos_in_list(c,pos1)) and nodename~="air" then
 			c[#(c)+1]=pos1
 		end
@@ -480,15 +847,19 @@
 	local dir = minetest.facedir_to_dir(node.param2)
 	local nnode=minetest.get_node(nnodepos)
 	local meta = minetest.get_meta(pos)
+	if meta:get_int("last_moved") == minetest.get_gametime() then
+		return
+	end
 	local owner = meta:get_string("owner")
 	if nnode.name == "technic:template" then
 		local connected_nodes=get_template_nodes(nnodepos)
 		move_nodes_vect(connected_nodes,dir,pos,owner)
 	end
+	minetest.get_meta(vector.add(pos, dir)):set_int("last_moved", minetest.get_gametime())
 end
 
 minetest.register_node("technic:template_motor",{
-	description = "Template motor",
+	description = S("Template Motor"),
 	tiles = {"pipeworks_filter_top.png^[transformR90", "technic_lv_cable.png", "technic_lv_cable.png",
 		"technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png"},
 	groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,mesecon=2},
@@ -499,3 +870,59 @@
 		meta:set_string("owner", placer:get_player_name())
 	end,
 })
+
+-- Crafts
+minetest.register_craft({
+	output = 'technic:frame_111111',
+	recipe = {
+		{'',			'default:stick',	''},
+		{'default:stick',	'technic:brass_ingot',	'default:stick'},
+		{'',			'default:stick',	''},
+	}
+})
+
+minetest.register_craft({
+	output = 'technic:frame_motor',
+	recipe = {
+		{'',					'technic:frame_111111',	''},
+		{'group:mesecon_conductor_craftable',	'technic:motor',	'group:mesecon_conductor_craftable'},
+		{'',					'technic:frame_111111',	''},
+	}
+})
+
+minetest.register_craft({
+	output = 'technic:template 10',
+	recipe = {
+		{'',			'technic:brass_ingot',	''},
+		{'technic:brass_ingot',	'default:mese_crystal',	'technic:brass_ingot'},
+		{'',			'technic:brass_ingot',	''},
+	}
+})
+
+minetest.register_craft({
+	output = 'technic:template_replacer',
+	recipe = {{'technic:template'}}
+})
+
+minetest.register_craft({
+	output = 'technic:template',
+	recipe = {{'technic:template_replacer'}}
+})
+
+minetest.register_craft({
+	output = 'technic:template_motor',
+	recipe = {
+		{'',					'technic:template',	''},
+		{'group:mesecon_conductor_craftable',	'technic:motor',	'group:mesecon_conductor_craftable'},
+		{'',					'technic:template',	''},
+	}
+})
+
+minetest.register_craft({
+	output = 'technic:template_tool',
+	recipe = {
+		{'',				'technic:template',	''},
+		{'default:mese_crystal',	'default:stick',	'default:mese_crystal'},
+		{'',				'default:stick',	''},
+	}
+})

--
Gitblit v1.8.0