est31
2015-06-18 a793747d92d9b1d93153c7fb4e0c82fe90624c78
commit | author | age
354ee6 1
S 2 local S = technic.getter
3
c06cdf 4 frames = {}
1524a9 5
b28001 6 local infinite_stacks = minetest.setting_getbool("creative_mode") and minetest.get_modpath("unified_inventory") == nil
N 7
8fba5e 8 local frames_pos = {}
N 9
c06cdf 10 -- Helpers
N 11
12 local function get_face(pos,ppos,pvect)
13     -- Raytracer to get which face has been clicked
478407 14     ppos={x=ppos.x-pos.x,y=ppos.y-pos.y+1.5,z=ppos.z-pos.z}
R 15     if pvect.x>0 then
16         local t=(-0.5-ppos.x)/pvect.x
17         local y_int=ppos.y+t*pvect.y
18         local z_int=ppos.z+t*pvect.z
68f7d3 19         if y_int>-0.45 and y_int<0.45 and z_int>-0.45 and z_int<0.45 then return 1 end 
478407 20     elseif pvect.x<0 then
R 21         local t=(0.5-ppos.x)/pvect.x
22         local y_int=ppos.y+t*pvect.y
23         local z_int=ppos.z+t*pvect.z
68f7d3 24         if y_int>-0.45 and y_int<0.45 and z_int>-0.45 and z_int<0.45 then return 2 end 
478407 25     end
R 26     if pvect.y>0 then
27         local t=(-0.5-ppos.y)/pvect.y
28         local x_int=ppos.x+t*pvect.x
29         local z_int=ppos.z+t*pvect.z
68f7d3 30         if x_int>-0.45 and x_int<0.45 and z_int>-0.45 and z_int<0.45 then return 3 end 
478407 31     elseif pvect.y<0 then
R 32         local t=(0.5-ppos.y)/pvect.y
33         local x_int=ppos.x+t*pvect.x
34         local z_int=ppos.z+t*pvect.z
68f7d3 35         if x_int>-0.45 and x_int<0.45 and z_int>-0.45 and z_int<0.45 then return 4 end 
478407 36     end
R 37     if pvect.z>0 then
38         local t=(-0.5-ppos.z)/pvect.z
39         local x_int=ppos.x+t*pvect.x
40         local y_int=ppos.y+t*pvect.y
68f7d3 41         if x_int>-0.45 and x_int<0.45 and y_int>-0.45 and y_int<0.45 then return 5 end 
478407 42     elseif pvect.z<0 then
R 43         local t=(0.5-ppos.z)/pvect.z
44         local x_int=ppos.x+t*pvect.x
45         local y_int=ppos.y+t*pvect.y
68f7d3 46         if x_int>-0.45 and x_int<0.45 and y_int>-0.45 and y_int<0.45 then return 6 end 
478407 47     end
R 48 end
49
5cf765 50 local function lines(str)
808d38 51     local t = {}
N 52     local function helper(line) table.insert(t, line) return "" end
53     helper((str:gsub("(.-)\r?\n", helper)))
54     return t
55 end
56
57 local function pos_to_string(pos)
58     if pos.x == 0 then pos.x = 0 end -- Fix for signed 0
59     if pos.y == 0 then pos.y = 0 end -- Fix for signed 0
60     if pos.z == 0 then pos.z = 0 end -- Fix for signed 0
61     return tostring(pos.x).."\n"..tostring(pos.y).."\n"..tostring(pos.z)
62 end
63
64 local function pos_from_string(str)
65     local l = lines(str)
66     return {x = tonumber(l[1]), y = tonumber(l[2]), z = tonumber(l[3])}
67 end
68
c06cdf 69 local function pos_in_list(l,pos)
N 70     for _,p in ipairs(l) do
71         if p.x==pos.x and p.y==pos.y and p.z==pos.z then return true end
72     end
73     return false
808d38 74 end
N 75
76 local function table_empty(table)
77     for _, __ in pairs(table) do
78         return false
79     end
80     return true
c06cdf 81 end
478407 82
c06cdf 83 local function add_table(table,toadd)
e1c995 84     local i = 1
c06cdf 85     while true do
e1c995 86         o = table[i]
N 87         if o == toadd then return end
88         if o == nil then break end
89         i = i+1
c06cdf 90     end
e1c995 91     table[i] = toadd
c06cdf 92 end
N 93
3cf0d3 94 local function move_nodes_vect(poslist,vect,must_not_move,owner)
N 95     if minetest.is_protected then
96         for _,pos in ipairs(poslist) do
66e4b5 97             local npos=vector.add(pos,vect)
3cf0d3 98             if minetest.is_protected(pos, owner) or minetest.is_protected(npos, owner) then
N 99                 return
100             end
101         end
102     end
c06cdf 103     for _,pos in ipairs(poslist) do
N 104         local npos=vector.add(pos,vect)
8c1be3 105         local name = minetest.get_node(npos).name
N 106         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
c06cdf 107             return
N 108         end
a73d56 109         --[[if pos.x==must_not_move.x and pos.y==must_not_move.y and pos.z==must_not_move.z then
c06cdf 110             return
a73d56 111         end]]
c06cdf 112     end
e1c995 113     local nodelist = {}
N 114     for _, pos in ipairs(poslist) do
115         local node = minetest.get_node(pos)
116         local meta = minetest.get_meta(pos):to_table()
117         nodelist[#(nodelist)+1] = {oldpos = pos, pos = vector.add(pos, vect), node = node, meta = meta}
c06cdf 118     end
e1c995 119     local objects = {}
N 120     for _, pos in ipairs(poslist) do
8c1be3 121         for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
e1c995 122             local entity = object:get_luaentity()
8da4d0 123             if not entity or not mesecon.is_mvps_unmov(entity.name) then
e1c995 124                 add_table(objects, object)
N 125             end
c06cdf 126         end
N 127     end
e1c995 128     for _, obj in ipairs(objects) do
N 129         obj:setpos(vector.add(obj:getpos(), vect))
c06cdf 130     end
N 131     for _,n in ipairs(nodelist) do
e1c995 132         local npos = n.pos
N 133         minetest.set_node(npos, n.node)
134         local meta = minetest.get_meta(npos)
c06cdf 135         meta:from_table(n.meta)
N 136         for __,pos in ipairs(poslist) do
e1c995 137             if npos.x == pos.x and npos.y == pos.y and npos.z == pos.z then
c06cdf 138                 table.remove(poslist, __)
N 139                 break
140             end
141         end
142     end
e1c995 143     for __, pos in ipairs(poslist) do
8c1be3 144         minetest.remove_node(pos)
c06cdf 145     end
e1c995 146     for _, callback in ipairs(mesecon.on_mvps_move) do
N 147         callback(nodelist)
148     end
c06cdf 149 end
N 150
8fba5e 151 local function is_supported_node(name)
N 152     return ((string.find(name, "tube") ~= nil) and (string.find(name, "pipeworks") ~= nil))
153 end
c06cdf 154
N 155
156 -- Frames
478407 157 for xm=0,1 do
R 158 for xp=0,1 do
159 for ym=0,1 do
160 for yp=0,1 do
161 for zm=0,1 do
162 for zp=0,1 do
163
164 local a=8/16
165 local b=7/16
166 local nodeboxes= {
167     { -a, -a, -a, -b,  a, -b },
168     { -a, -a,  b, -b,  a,  a },
169     {  b, -a,  b,  a,  a,  a },
170     {  b, -a, -a,  a,  a, -b },
171
172     { -b,  b, -a,  b,  a, -b },
173     { -b, -a, -a,  b, -b, -b },
174     
175     { -b,  b,  b,  b,  a,  a },
176     { -b, -a,  b,  b, -b,  a },
177
178     {  b,  b, -b,  a,  a,  b },
179     {  b, -a, -b,  a, -b,  b },
180
181     { -a,  b, -b, -b,  a,  b },
182     { -a, -a, -b, -b, -b,  b },
183     }
184     
185     if yp==0 then
186         table.insert(nodeboxes, {-b,b,-b, b,a,b})
187     end
188     if ym==0 then
189         table.insert(nodeboxes, {-b,-a,-b, b,-b,b})
190     end
191     if xp==0 then
192         table.insert(nodeboxes, {b,b,b,a,-b,-b})
193     end
194     if xm==0 then
195         table.insert(nodeboxes, {-a,-b,-b,-b,b,b})
196     end
197     if zp==0 then
198         table.insert(nodeboxes, {-b,-b,b, b,b,a})
199     end
200     if zm==0 then
201         table.insert(nodeboxes, {-b,-b,-a, b,b,-b})
202     end
203     
204     local nameext=tostring(xm)..tostring(xp)..tostring(ym)..tostring(yp)..tostring(zm)..tostring(zp)
205     local groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}
206     if nameext~="111111" then groups.not_in_creative_inventory=1 end
207     
208
209     minetest.register_node("technic:frame_"..nameext,{
354ee6 210         description = S("Frame"),
478407 211         tiles = {"technic_frame.png"},
R 212         groups=groups,
213         drawtype = "nodebox",
214         node_box = {
215             type = "fixed",
216         fixed=nodeboxes,
217         },
3a5215 218         selection_box = {
N 219             type="fixed",
220             fixed={-0.5,-0.5,-0.5,0.5,0.5,0.5}
221         },
478407 222         paramtype = "light",
R 223         frame=1,
224         drop="technic:frame_111111",
b28001 225         sunlight_propagates = true,
8fba5e 226         frame_connect_all=function(nodename)
478407 227             l2={}
R 228             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}}
229             for i,dir in ipairs(l1) do
230                 if string.sub(nodename,-7+i,-7+i)=="1" then
231                     l2[#(l2)+1]=dir
232                 end
233             end
234             return l2
235         end,
236         on_punch=function(pos,node,puncher)
237             local ppos=puncher:getpos()
238             local pvect=puncher:get_look_dir()
239             local pface=get_face(pos,ppos,pvect)
240             if pface==nil then return end
241             local nodename=node.name
242             local newstate=tostring(1-tonumber(string.sub(nodename,-7+pface,-7+pface)))
243             if pface<=5 then
244                 nodename=string.sub(nodename,1,-7+pface-1)..newstate..string.sub(nodename,-7+pface+1)
245             else
246                 nodename=string.sub(nodename,1,-2)..newstate
247             end
248             node.name=nodename
8c1be3 249             minetest.set_node(pos,node)
68f7d3 250         end,
N 251         on_place = function(itemstack, placer, pointed_thing)
252             local pos = pointed_thing.above
52e701 253             if minetest.is_protected(pos, placer:get_player_name()) then
N 254                 minetest.log("action", placer:get_player_name()
255                     .. " tried to place " .. itemstack:get_name()
256                     .. " at protected position "
257                     .. minetest.pos_to_string(pos))
258                 minetest.record_protection_violation(pos, placer:get_player_name())
259                 return itemstack
260             end
68f7d3 261             if pos == nil then return end
N 262             local node = minetest.get_node(pos)
263             if node.name ~= "air" then
8fba5e 264                 if is_supported_node(node.name) then
N 265                     obj = minetest.add_entity(pos, "technic:frame_entity")
266                     obj:get_luaentity():set_node({name=itemstack:get_name()})
267                 end
68f7d3 268             else
N 269                 minetest.set_node(pos, {name = itemstack:get_name()})
52e701 270             end
b28001 271             if not infinite_stacks then
N 272                 itemstack:take_item()
273             end
52e701 274             return itemstack
N 275         end,
b28001 276         on_rightclick = function(pos, node, placer, itemstack, pointed_thing)
52e701 277             if is_supported_node(itemstack:get_name()) then
N 278                 if minetest.is_protected(pos, placer:get_player_name()) then
279                     minetest.log("action", placer:get_player_name()
280                         .. " tried to place " .. itemstack:get_name()
281                         .. " at protected position "
282                         .. minetest.pos_to_string(pos))
283                     minetest.record_protection_violation(pos, placer:get_player_name())
284                     return itemstack
285                 end
286                 
287                 minetest.set_node(pos, {name = itemstack:get_name()})
288                 
289                 local take_item = true
290                 local def = minetest.registered_items[itemstack:get_name()]
291                 -- Run callback
292                 if def.after_place_node then
293                     -- Copy place_to because callback can modify it
294                     local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
295                     if def.after_place_node(pos_copy, placer, itemstack) then
296                         take_item = false
297                     end
298                 end
299
300                 -- Run script hook
301                 local _, callback
302                 for _, callback in ipairs(minetest.registered_on_placenodes) do
303                     -- Copy pos and node because callback can modify them
304                     local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
305                     local newnode_copy = {name=def.name, param1=0, param2=0}
306                     local oldnode_copy = {name="air", param1=0, param2=0}
307                     if callback(pos_copy, newnode_copy, placer, oldnode_copy, itemstack) then
308                         take_item = false
309                     end
310                 end
311
312                 if take_item then
313                     itemstack:take_item()
314                 end
315                 
316                 obj = minetest.add_entity(pos, "technic:frame_entity")
317                 obj:get_luaentity():set_node({name=node.name})
318                 
319                 return itemstack
b28001 320             else
N 321                 --local pointed_thing = {type = "node", under = pos}
322                 if pointed_thing then
323                     minetest.item_place_node(itemstack, placer, pointed_thing)
324                 end
68f7d3 325             end
N 326         end,
478407 327     })
R 328
329 end
330 end
331 end
332 end
333 end
334 end
335
68f7d3 336 minetest.register_entity("technic:frame_entity", {
N 337     initial_properties = {
338         physical = true,
339         collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
340         visual = "wielditem",
341         textures = {},
342         visual_size = {x=0.667, y=0.667},
343     },
c06cdf 344
68f7d3 345     node = {},
c06cdf 346
68f7d3 347     set_node = function(self, node)
N 348         self.node = node
8fba5e 349         local pos = self.object:getpos()
N 350         pos = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)}
351         frames_pos[pos_to_string(pos)] = node.name
68f7d3 352         local stack = ItemStack(node.name)
N 353         local itemtable = stack:to_table()
354         local itemname = nil
355         if itemtable then
356             itemname = stack:to_table().name
357         end
358         local item_texture = nil
359         local item_type = ""
360         if minetest.registered_items[itemname] then
361             item_texture = minetest.registered_items[itemname].inventory_image
362             item_type = minetest.registered_items[itemname].type
363         end
364         prop = {
365             is_visible = true,
366             textures = {node.name},
367         }
368         self.object:set_properties(prop)
369     end,
370
371     get_staticdata = function(self)
372         return self.node.name
373     end,
374
375     on_activate = function(self, staticdata)
376         self.object:set_armor_groups({immortal=1})
377         self:set_node({name=staticdata})
378     end,
379     
380     dig = function(self)
381         minetest.handle_node_drops(self.object:getpos(), {ItemStack("technic:frame_111111")}, self.last_puncher)
8fba5e 382         local pos = self.object:getpos()
N 383         pos = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)}
384         frames_pos[pos_to_string(pos)] = nil
68f7d3 385         self.object:remove()
N 386     end,
387     
388     on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
389         local pos = self.object:getpos()
390         if self.damage_object == nil then
391             self.damage_object = minetest.add_entity(pos, "technic:damage_entity")
392             self.damage_object:get_luaentity().remaining_time = 0.25
393             self.damage_object:get_luaentity().frame_object = self
394             self.damage_object:get_luaentity().texture_index = 0
395             self.damage_object:get_luaentity().texture_change_time = 0.15
396         else
397             self.damage_object:get_luaentity().remaining_time = 0.25
398         end
399         self.last_puncher = puncher
400         local ppos = puncher:getpos()
401         local pvect = puncher:get_look_dir()
402         local pface = get_face(pos,ppos,pvect)
403         if pface == nil then return end
404         local nodename = self.node.name
405         local newstate = tostring(1-tonumber(string.sub(nodename, -7+pface, -7+pface)))
406         if pface <= 5 then
407             nodename = string.sub(nodename, 1, -7+pface-1)..newstate..string.sub(nodename, -7+pface+1)
408         else
409             nodename = string.sub(nodename, 1, -2)..newstate
410         end
411         self.node.name = nodename
412         self:set_node(self.node)
413     end,
414     
415     on_rightclick = function(self, clicker)
416         local pos = self.object:getpos()
417         local ppos = clicker:getpos()
418         local pvect = clicker:get_look_dir()
419         local pface = get_face(pos, ppos, pvect)
420         if pface == nil then return end
421         local pos_under = {x = math.floor(pos.x+0.5), y = math.floor(pos.y+0.5), z = math.floor(pos.z+0.5)}
422         local pos_above = {x = pos_under.x, y = pos_under.y, z = pos_under.z}
423         local index = ({"x", "y", "z"})[math.floor((pface+1)/2)]
424         pos_above[index] = pos_above[index] + 2*((pface+1)%2) - 1
425         local pointed_thing = {type = "node", under = pos_under, above = pos_above}
426         local itemstack = clicker:get_wielded_item()
427         local itemdef = minetest.registered_items[itemstack:get_name()]
428         if itemdef ~= nil then
429             itemdef.on_place(itemstack, clicker, pointed_thing)
430         end
431     end,
432 })
433
434 local crack = "crack_anylength.png^[verticalframe:5:0"
435 minetest.register_entity("technic:damage_entity", {
436     initial_properties = {
437         visual = "cube",
438         visual_size = {x=1.01, y=1.01},
439         textures = {crack, crack, crack, crack, crack, crack},
440         collisionbox = {0, 0, 0, 0, 0, 0},
441         physical = false,
442     },
443     on_step = function(self, dtime)
444         if self.remaining_time == nil then
445             self.object:remove()
446             self.frame_object.damage_object = nil
447         end
448         self.remaining_time = self.remaining_time - dtime
449         if self.remaining_time < 0 then
450             self.object:remove()
451             self.frame_object.damage_object = nil
452         end
453         self.texture_change_time = self.texture_change_time - dtime
454         if self.texture_change_time < 0 then
455             self.texture_change_time = self.texture_change_time + 0.15
456             self.texture_index = self.texture_index + 1
457             if self.texture_index == 5 then
458                 self.object:remove()
459                 self.frame_object.damage_object = nil
460                 self.frame_object:dig()
461             end
462             local ct = "crack_anylength.png^[verticalframe:5:"..self.texture_index
463             self.object:set_properties({textures = {ct, ct, ct, ct, ct, ct}})
464         end
465     end,
466 })
c06cdf 467
8da4d0 468 mesecon.register_mvps_unmov("technic:frame_entity")
VE 469 mesecon.register_mvps_unmov("technic:damage_entity")
470 mesecon.register_on_mvps_move(function(moved_nodes)
52e701 471     local to_move = {}
N 472     for _, n in ipairs(moved_nodes) do
473         if frames_pos[pos_to_string(n.oldpos)] ~= nil then
474             to_move[#to_move+1] = {pos = n.pos, oldpos = n.oldpos, name = frames_pos[pos_to_string(n.oldpos)]}
475             frames_pos[pos_to_string(n.oldpos)] = nil
476         end
477     end
478     if #to_move > 0 then
479         for _, t in ipairs(to_move) do
480             frames_pos[pos_to_string(t.pos)] = t.name
481             local objects = minetest.get_objects_inside_radius(t.oldpos, 0.1)
482             for _, obj in ipairs(objects) do
483                 local entity = obj:get_luaentity()
484                 if entity and (entity.name == "technic:frame_entity" or entity.name == "technic:damage_entity") then
485                     obj:setpos(t.pos)
486                 end
487             end
488         end
489     end
490 end)
491
492 minetest.register_on_dignode(function(pos, node)
493     if frames_pos[pos_to_string(pos)] ~= nil then
494         minetest.set_node(pos, {name = frames_pos[pos_to_string(pos)]})
495         frames_pos[pos_to_string(pos)] = nil
496         local objects = minetest.get_objects_inside_radius(pos, 0.1)
497         for _, obj in ipairs(objects) do
498             local entity = obj:get_luaentity()
499             if entity and (entity.name == "technic:frame_entity" or entity.name == "technic:damage_entity") then
500                 obj:remove()
501             end
502         end
503     end
504 end)
505
c06cdf 506 -- Frame motor
N 507 local function connected(pos,c,adj)
508     for _,vect in ipairs(adj) do
509         local pos1=vector.add(pos,vect)
8fba5e 510         local nodename=minetest.get_node(pos1).name
N 511         if frames_pos[pos_to_string(pos1)] then
512             nodename = frames_pos[pos_to_string(pos1)]
513         end
c06cdf 514         if not(pos_in_list(c,pos1)) and nodename~="air" and
N 515         (minetest.registered_nodes[nodename].frames_can_connect==nil or
516         minetest.registered_nodes[nodename].frames_can_connect(pos1,vect)) then
517             c[#(c)+1]=pos1
518             if minetest.registered_nodes[nodename].frame==1 then
8fba5e 519                 local adj=minetest.registered_nodes[nodename].frame_connect_all(nodename)
c06cdf 520                 connected(pos1,c,adj)
N 521             end
522         end
523     end
524 end
525
526 local function get_connected_nodes(pos)
527     c={pos}
8c1be3 528     local nodename=minetest.get_node(pos).name
8fba5e 529     if frames_pos[pos_to_string(pos)] then
N 530         nodename = frames_pos[pos_to_string(pos)]
531     end
532     connected(pos,c,minetest.registered_nodes[nodename].frame_connect_all(nodename))
c06cdf 533     return c
N 534 end
535
536 local function frame_motor_on(pos, node)
48ea6f 537     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}}
c06cdf 538     local nnodepos = vector.add(pos, dirs[math.floor(node.param2/4)+1])
48ea6f 539     local dir = minetest.facedir_to_dir(node.param2)
N 540     local nnode=minetest.get_node(nnodepos)
8fba5e 541     if frames_pos[pos_to_string(nnodepos)] then
N 542         nnode.name = frames_pos[pos_to_string(nnodepos)]
543     end
a579ee 544     local meta = minetest.get_meta(pos)
6a0807 545     if meta:get_int("last_moved") == minetest.get_gametime() then
N 546         return
547     end
a579ee 548     local owner = meta:get_string("owner")
478407 549     if minetest.registered_nodes[nnode.name].frame==1 then
48ea6f 550         local connected_nodes=get_connected_nodes(nnodepos)
a579ee 551         move_nodes_vect(connected_nodes,dir,pos,owner)
478407 552     end
6a0807 553     minetest.get_meta(vector.add(pos, dir)):set_int("last_moved", minetest.get_gametime())
478407 554 end
R 555
48ea6f 556 minetest.register_node("technic:frame_motor",{
354ee6 557     description = S("Frame Motor"),
48ea6f 558     tiles = {"pipeworks_filter_top.png^[transformR90", "technic_lv_cable.png", "technic_lv_cable.png",
478407 559         "technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png"},
R 560     groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,mesecon=2},
561     paramtype2 = "facedir",
48ea6f 562     mesecons={effector={action_on=frame_motor_on}},
a579ee 563     after_place_node = function(pos, placer, itemstack)
N 564         local meta = minetest.get_meta(pos)
565         meta:set_string("owner", placer:get_player_name())
566     end,
478407 567     frames_can_connect=function(pos,dir)
48ea6f 568         local node = minetest.get_node(pos)
N 569         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]
570         return dir2.x~=-dir.x or dir2.y~=-dir.y or dir2.z~=-dir.z
478407 571     end
R 572 })
573
574
c06cdf 575
N 576 -- Templates
808d38 577 local function template_connected(pos,c,connectors)
c06cdf 578     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
N 579         local pos1=vector.add(pos,vect)
580         local nodename=minetest.get_node(pos1).name
808d38 581         if not(pos_in_list(c,pos1)) and (nodename=="technic:template" or nodename == "technic:template_connector")then
a73d56 582             local meta = minetest.get_meta(pos1)
N 583             if meta:get_string("connected") == "" then
584                 c[#(c)+1]=pos1
808d38 585                 template_connected(pos1,c,connectors)
N 586                 if nodename == "technic:template_connector" then
587                     connectors[#connectors+1] = pos1
588                 end
a73d56 589             end
a579ee 590         end
478407 591     end
R 592 end
593
c06cdf 594 local function get_templates(pos)
808d38 595     local c = {pos}
N 596     local connectors
597     if minetest.get_node(pos).name == "technic:template_connector" then
598         connectors = {pos}
599     else
600         connectors = {}
601     end
602     template_connected(pos,c,connectors)
603     return c, connectors
604 end
605
606 local function swap_template(pos, new)
607     local meta = minetest.get_meta(pos)
608     local saved_node = meta:get_string("saved_node")
609     meta:set_string("saved_node", "")
f3d8b4 610     technic.swap_node(pos, new)
808d38 611     local meta = minetest.get_meta(pos)
N 612     meta:set_string("saved_node", saved_node)
478407 613 end
R 614
c06cdf 615 local function save_node(pos)
N 616     local node = minetest.get_node(pos)
808d38 617     if node.name == "air" then
N 618         minetest.set_node(pos, {name="technic:template"})
619         return
620     end
621     if node.name == "technic:template" then
622         swap_template(pos, "technic:template_connector")
623         local meta = minetest.get_meta(pos)
624         meta:set_string("connected", "")
625         return
626     end
c06cdf 627     local meta = minetest.get_meta(pos)
N 628     local meta0 = meta:to_table()
629     for _, list in pairs(meta0.inventory) do
630         for key, stack in pairs(list) do
631             list[key] = stack:to_string()
632         end
478407 633     end
c06cdf 634     node.meta = meta0
808d38 635     minetest.set_node(pos, {name="technic:template"})
c06cdf 636     return node
478407 637 end
R 638
c06cdf 639 local function restore_node(pos, node)
N 640     minetest.set_node(pos, node)
641     local meta = minetest.get_meta(pos)
642     for _, list in pairs(node.meta.inventory) do
643         for key, stack in pairs(list) do
644             list[key] = ItemStack(stack)
645         end
646     end
647     meta:from_table(node.meta)
648 end
649
650 local function expand_template(pos)
651     local meta = minetest.get_meta(pos)
652     local c = meta:get_string("connected")
653     if c == "" then return end
654     c = minetest.deserialize(c)
655     for _, vect in ipairs(c) do
808d38 656         local pos1 = vector.add(pos, vect)
N 657         local saved_node = save_node(pos1)
658         local meta1 = minetest.get_meta(pos1)
659         if saved_node ~= nil then
660             meta1:set_string("saved_node", minetest.serialize(saved_node))
661         else
662             --meta1:set_string("saved_node", "")
663         end
664     end
665 end
666
667 local function compress_templates(pos)
668     local templates, connectors = get_templates(pos)
669     if #connectors == 0 then
670         connectors = {pos}
671     end
672     for _, cn in ipairs(connectors) do
673         local meta = minetest.get_meta(cn)
674         local c = {}
675         for _,p in ipairs(templates) do
676             local np = vector.subtract(p, cn)
677             if not pos_in_list(c,np) then
678                 c[#c+1] = np
478407 679             end
808d38 680         end
N 681         local cc = {}
682         for _,p in ipairs(connectors) do
683             local np = vector.subtract(p, cn)
684             if (np.x ~= 0 or np.y ~= 0 or np.z ~= 0) then
685                 cc[pos_to_string(np)] = true
686             end
687         end
688         swap_template(cn, "technic:template")
689         meta:set_string("connected", minetest.serialize(c))
690         meta:set_string("connectors_connected", minetest.serialize(cc))
691     end
692     
693     for _,p in ipairs(templates) do
694         if not pos_in_list(connectors, p) then
695             minetest.set_node(p, {name = "air"})
478407 696         end
R 697     end
698 end
699
48d571 700 local function template_drops(pos, node, oldmeta, digger)
N 701     local c = oldmeta.fields.connected
808d38 702     local cc = oldmeta.fields.connectors_connected
48d571 703     local drops
N 704     if c == "" or c == nil then
705         drops = {"technic:template 1"}
706     else
808d38 707         if cc == "" or cc == nil then
N 708             drops = {"technic:template 1"}
709         else
710             local dcc = minetest.deserialize(cc)
711             if not table_empty(dcc) then
712                 drops = {}
713                 for sp, _ in pairs(dcc) do
714                     local ssp = pos_from_string(sp)
715                     local p = vector.add(ssp, pos)
716                     local meta = minetest.get_meta(p)
717                     local d = minetest.deserialize(meta:get_string("connectors_connected"))
718                     if d ~= nil then
719                         d[pos_to_string({x=-ssp.x, y=-ssp.y, z=-ssp.z})] = nil
720                         meta:set_string("connectors_connected", minetest.serialize(d))
721                     end
722                 end
723             else
724                 local stack_max = 99
725                 local num = #(minetest.deserialize(c))
726                 drops = {}
727                 while num > stack_max do
728                     drops[#drops+1] = "technic:template "..stack_max
729                     num = num - stack_max
730                 end
731                 drops[#drops+1] = "technic:template "..num
732             end
48d571 733         end
N 734     end
735     minetest.handle_node_drops(pos, drops, digger)
808d38 736 end
N 737
738 local function template_on_destruct(pos, node)
739     local meta = minetest.get_meta(pos)
740     local saved_node = meta:get_string("saved_node")
741     if saved_node ~= "" then
742         local nnode = minetest.deserialize(saved_node)
743         minetest.after(0, restore_node, pos, nnode)
744     end
48d571 745 end
N 746
c06cdf 747 minetest.register_node("technic:template",{
354ee6 748     description = S("Template"),
c06cdf 749     tiles = {"technic_mv_cable.png"},
48d571 750     drop = "",
c06cdf 751     groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
808d38 752     on_destruct = template_on_destruct,
48d571 753     after_dig_node = template_drops,
c06cdf 754     on_punch = function(pos,node,puncher)
808d38 755         swap_template(pos, "technic:template_disabled")
c06cdf 756     end
N 757 })
758
759 minetest.register_node("technic:template_disabled",{
354ee6 760     description = S("Template"),
c06cdf 761     tiles = {"technic_hv_cable.png"},
48d571 762     drop = "",
808d38 763     groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
N 764     on_destruct = template_on_destruct,
48d571 765     after_dig_node = template_drops,
c06cdf 766     on_punch = function(pos,node,puncher)
808d38 767     local meta = minetest.get_meta(pos)
N 768         swap_template(pos, "technic:template_connector")
769     end
770 })
771
772 minetest.register_node("technic:template_connector",{
354ee6 773     description = S("Template"),
808d38 774     tiles = {"technic_lv_cable.png"},
N 775     drop = "",
776     groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
777     on_destruct = template_on_destruct,
778     after_dig_node = template_drops,
779     on_punch = function(pos,node,puncher)
780         swap_template(pos, "technic:template")
c06cdf 781     end
N 782 })
783
784 minetest.register_craftitem("technic:template_replacer",{
354ee6 785     description = S("Template (replacing)"),
c06cdf 786     inventory_image = "technic_template_replacer.png",
N 787     on_place = function(itemstack, placer, pointed_thing)
788         local p = pointed_thing.under
789         if minetest.is_protected and minetest.is_protected(p, placer:get_player_name()) then
790             return nil
791         end
792         local node = minetest.get_node(p)
793         if node.name == "technic:template" then return end
794         local saved_node = save_node(p)
795         itemstack:take_item()
796         if saved_node ~= nil then
797             local meta = minetest.get_meta(p)
798             meta:set_string("saved_node", minetest.serialize(saved_node))
799         end
800         return itemstack
801     end
802 })
803
804 minetest.register_tool("technic:template_tool",{
39c41a 805     description = S("Template Tool"),
c06cdf 806     inventory_image = "technic_template_tool.png",
N 807     on_use = function(itemstack, puncher, pointed_thing)
808         local pos = pointed_thing.under
061d1a 809         if pos == nil or (minetest.is_protected and minetest.is_protected(pos, puncher:get_player_name())) then
c06cdf 810             return nil
N 811         end
812         local node = minetest.get_node(pos)
808d38 813         if node.name ~= "technic:template" and node.name ~= "technic:template_connector" then return end
c06cdf 814         local meta = minetest.get_meta(pos)
N 815         local c2 = meta:get_string("connected")
816         if c2 ~= "" then
817             expand_template(pos)
808d38 818         else
N 819             compress_templates(pos)
c06cdf 820         end
808d38 821         
c06cdf 822     end
N 823 })
824
825
826
827 -- Template motor
828 local function get_template_nodes(pos)
829     local meta = minetest.get_meta(pos)
830     local connected = meta:get_string("connected")
831     if connected == "" then return {} end
832     local adj = minetest.deserialize(connected)
833     local c = {}
834     for _,vect in ipairs(adj) do
835         local pos1=vector.add(pos,vect)
8c1be3 836         local nodename=minetest.get_node(pos1).name
c06cdf 837         if not(pos_in_list(c,pos1)) and nodename~="air" then
N 838             c[#(c)+1]=pos1
839         end
840     end
841     return c
842 end
843
844 local function template_motor_on(pos, node)
845     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}}
846     local nnodepos = vector.add(pos, dirs[math.floor(node.param2/4)+1])
847     local dir = minetest.facedir_to_dir(node.param2)
848     local nnode=minetest.get_node(nnodepos)
3cf0d3 849     local meta = minetest.get_meta(pos)
6a0807 850     if meta:get_int("last_moved") == minetest.get_gametime() then
N 851         return
852     end
3cf0d3 853     local owner = meta:get_string("owner")
c06cdf 854     if nnode.name == "technic:template" then
N 855         local connected_nodes=get_template_nodes(nnodepos)
3cf0d3 856         move_nodes_vect(connected_nodes,dir,pos,owner)
c06cdf 857     end
6a0807 858     minetest.get_meta(vector.add(pos, dir)):set_int("last_moved", minetest.get_gametime())
c06cdf 859 end
N 860
861 minetest.register_node("technic:template_motor",{
39c41a 862     description = S("Template Motor"),
c06cdf 863     tiles = {"pipeworks_filter_top.png^[transformR90", "technic_lv_cable.png", "technic_lv_cable.png",
N 864         "technic_lv_cable.png", "technic_lv_cable.png", "technic_lv_cable.png"},
865     groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2,mesecon=2},
866     paramtype2 = "facedir",
867     mesecons={effector={action_on=template_motor_on}},
3cf0d3 868     after_place_node = function(pos, placer, itemstack)
N 869         local meta = minetest.get_meta(pos)
870         meta:set_string("owner", placer:get_player_name())
871     end,
c06cdf 872 })
768794 873
N 874 -- Crafts
875 minetest.register_craft({
876     output = 'technic:frame_111111',
877     recipe = {
878         {'',            'default:stick',    ''},
879         {'default:stick',    'technic:brass_ingot',    'default:stick'},
880         {'',            'default:stick',    ''},
881     }
882 })
883
884 minetest.register_craft({
885     output = 'technic:frame_motor',
886     recipe = {
887         {'',                    'technic:frame_111111',    ''},
44dbc7 888         {'group:mesecon_conductor_craftable',    'technic:motor',    'group:mesecon_conductor_craftable'},
768794 889         {'',                    'technic:frame_111111',    ''},
N 890     }
891 })
892
893 minetest.register_craft({
894     output = 'technic:template 10',
895     recipe = {
896         {'',            'technic:brass_ingot',    ''},
897         {'technic:brass_ingot',    'default:mese_crystal',    'technic:brass_ingot'},
898         {'',            'technic:brass_ingot',    ''},
899     }
900 })
901
902 minetest.register_craft({
903     output = 'technic:template_replacer',
904     recipe = {{'technic:template'}}
905 })
906
907 minetest.register_craft({
908     output = 'technic:template',
909     recipe = {{'technic:template_replacer'}}
910 })
911
912 minetest.register_craft({
913     output = 'technic:template_motor',
914     recipe = {
915         {'',                    'technic:template',    ''},
44dbc7 916         {'group:mesecon_conductor_craftable',    'technic:motor',    'group:mesecon_conductor_craftable'},
768794 917         {'',                    'technic:template',    ''},
N 918     }
919 })
920
921 minetest.register_craft({
922     output = 'technic:template_tool',
923     recipe = {
924         {'',                'technic:template',    ''},
925         {'default:mese_crystal',    'default:stick',    'default:mese_crystal'},
926         {'',                'default:stick',    ''},
927     }
928 })