Elias Åström d74c250a40 Preserve active timers at frame move
Previously timers were not copied over to the new nodes when frames
move.  This lead to blinky plants from mesecons to stop working after a
platform has moved, and buttons getting stuck in their pressed state.

Now the timers state for active timers are copied from the old node
positions to the new node positions.
2018-08-25 12:24:58 +02:00

943 lines
28 KiB
Lua

local S = technic.getter
frames = {}
local infinite_stacks = minetest.settings:get_bool("creative_mode") and minetest.get_modpath("unified_inventory") == nil
local frames_pos = {}
-- Helpers
local function get_face(pos,ppos,pvect)
-- Raytracer to get which face has been clicked
ppos={x=ppos.x-pos.x,y=ppos.y-pos.y+1.5,z=ppos.z-pos.z}
if 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.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.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.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.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.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.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)
for _,p in ipairs(l) do
if p.x==pos.x and p.y==pos.y and p.z==pos.z then return true end
end
return false
end
local function table_empty(table)
for _, __ in pairs(table) do
return false
end
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)
if minetest.is_protected then
for _,pos in ipairs(poslist) do
local npos=vector.add(pos,vect)
if minetest.is_protected(pos, owner) or minetest.is_protected(npos, owner) then
return
end
end
end
for _,pos in ipairs(poslist) do
local npos=vector.add(pos,vect)
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
local nodelist = {}
for _, pos in ipairs(poslist) do
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos):to_table()
local timer = minetest.get_node_timer(pos)
nodelist[#nodelist+1] = {
oldpos = pos,
pos = vector.add(pos, vect),
node = node,
meta = meta,
timer = {
timeout = timer:get_timeout(),
elapsed = timer:get_elapsed()
}
}
end
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))
end
for _,n in ipairs(nodelist) do
local npos = n.pos
minetest.set_node(npos, n.node)
local meta = minetest.get_meta(npos)
meta:from_table(n.meta)
local timer = minetest.get_node_timer(npos)
if n.timer.timeout ~= 0 or n.timer.elapsed ~= 0 then
timer:set(n.timer.timeout, n.timer.elapsed)
end
for __,pos in ipairs(poslist) do
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.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
for xm=0,1 do
for xp=0,1 do
for ym=0,1 do
for yp=0,1 do
for zm=0,1 do
for zp=0,1 do
local a=8/16
local b=7/16
local nodeboxes= {
{ -a, -a, -a, -b, a, -b },
{ -a, -a, b, -b, a, a },
{ b, -a, b, a, a, a },
{ b, -a, -a, a, a, -b },
{ -b, b, -a, b, a, -b },
{ -b, -a, -a, b, -b, -b },
{ -b, b, b, b, a, a },
{ -b, -a, b, b, -b, a },
{ b, b, -b, a, a, b },
{ b, -a, -b, a, -b, b },
{ -a, b, -b, -b, a, b },
{ -a, -a, -b, -b, -b, b },
}
if yp==0 then
table.insert(nodeboxes, {-b,b,-b, b,a,b})
end
if ym==0 then
table.insert(nodeboxes, {-b,-a,-b, b,-b,b})
end
if xp==0 then
table.insert(nodeboxes, {b,b,b,a,-b,-b})
end
if xm==0 then
table.insert(nodeboxes, {-a,-b,-b,-b,b,b})
end
if zp==0 then
table.insert(nodeboxes, {-b,-b,b, b,b,a})
end
if zm==0 then
table.insert(nodeboxes, {-b,-b,-a, b,b,-b})
end
local nameext=tostring(xm)..tostring(xp)..tostring(ym)..tostring(yp)..tostring(zm)..tostring(zp)
local groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}
if nameext~="111111" then groups.not_in_creative_inventory=1 end
minetest.register_node("technic:frame_"..nameext,{
description = S("Frame"),
tiles = {"technic_frame.png"},
groups=groups,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed=nodeboxes,
},
selection_box = {
type="fixed",
fixed={-0.5,-0.5,-0.5,0.5,0.5,0.5}
},
paramtype = "light",
frame=1,
drop="technic:frame_111111",
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
if string.sub(nodename,-7+i,-7+i)=="1" then
l2[#(l2)+1]=dir
end
end
return l2
end,
on_punch=function(pos,node,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=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
node.name=nodename
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
return minetest.item_place_node(itemstack, placer, pointed_thing)
end
end
end,
})
end
end
end
end
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.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(nodename)
connected(pos1,c,adj)
end
end
end
end
local function get_connected_nodes(pos)
c={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
local function frame_motor_on(pos, node)
local dirs = {{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}}
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 = 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},
paramtype2 = "facedir",
mesecons={effector={action_on=frame_motor_on}},
after_place_node = function(pos, placer, itemstack)
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
end,
frames_can_connect=function(pos,dir)
local node = minetest.get_node(pos)
local dir2 = ({{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}})[math.floor(node.param2/4)+1]
return dir2.x~=-dir.x or dir2.y~=-dir.y or dir2.z~=-dir.z
end
})
-- Templates
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" 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,connectors)
if nodename == "technic:template_connector" then
connectors[#connectors+1] = pos1
end
end
end
end
end
local function get_templates(pos)
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" 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
for key, stack in pairs(list) do
list[key] = stack:to_string()
end
end
node.meta = meta0
minetest.set_node(pos, {name="technic:template"})
return node
end
local function restore_node(pos, node)
minetest.set_node(pos, node)
local meta = minetest.get_meta(pos)
for _, list in pairs(node.meta.inventory) do
for key, stack in pairs(list) do
list[key] = ItemStack(stack)
end
end
meta:from_table(node.meta)
end
local function expand_template(pos)
local meta = minetest.get_meta(pos)
local c = meta:get_string("connected")
if c == "" then return end
c = minetest.deserialize(c)
for _, vect in ipairs(c) do
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
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
end
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 = S("Template"),
tiles = {"technic_mv_cable.png"},
drop = "",
groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
on_destruct = template_on_destruct,
after_dig_node = template_drops,
on_punch = function(pos,node,puncher)
swap_template(pos, "technic:template_disabled")
end
})
minetest.register_node("technic:template_disabled",{
description = S("Template"),
tiles = {"technic_hv_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)
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 = S("Template (replacing)"),
inventory_image = "technic_template_replacer.png",
on_place = function(itemstack, placer, pointed_thing)
local p = pointed_thing.under
if minetest.is_protected and minetest.is_protected(p, placer:get_player_name()) then
return nil
end
local node = minetest.get_node(p)
if node.name == "technic:template" then return end
local saved_node = save_node(p)
itemstack:take_item()
if saved_node ~= nil then
local meta = minetest.get_meta(p)
meta:set_string("saved_node", minetest.serialize(saved_node))
end
return itemstack
end
})
minetest.register_tool("technic: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, puncher:get_player_name())) then
return nil
end
local node = minetest.get_node(pos)
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)
else
compress_templates(pos)
end
end
})
-- Template motor
local function get_template_nodes(pos)
local meta = minetest.get_meta(pos)
local connected = meta:get_string("connected")
if connected == "" then return {} end
local adj = minetest.deserialize(connected)
local c = {}
for _,vect in ipairs(adj) do
local pos1=vector.add(pos,vect)
local nodename=minetest.get_node(pos1).name
if not(pos_in_list(c,pos1)) and nodename~="air" then
c[#(c)+1]=pos1
end
end
return c
end
local function template_motor_on(pos, node)
local dirs = {{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}}
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)
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 = 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},
paramtype2 = "facedir",
mesecons={effector={action_on=template_motor_on}},
after_place_node = function(pos, placer, itemstack)
local meta = minetest.get_meta(pos)
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', ''},
}
})