1 dofile(pipeworks
.modpath
.."/compat.lua")
3 --and an extra function for getting the right-facing vector
4 local function facedir_to_right_dir(facedir
)
6 --find the other directions
7 local backdir
= minetest
.facedir_to_dir(facedir
)
8 local topdir
= ({[0]={x
=0, y
=1, z
=0},
13 {x
=0, y
=-1, z
=0}})[math
.floor(facedir
/4)]
15 --return a cross product
16 return {x
=topdir
.y
*backdir
.z
- backdir
.y
*topdir
.z
,
17 y
=topdir
.z
*backdir
.x
- backdir
.z
*topdir
.x
,
18 z
=topdir
.x
*backdir
.y
- backdir
.x
*topdir
.y
}
22 get_player_name
= function() return ":pipeworks" end,
23 -- any other player functions called by allow_metadata_inventory_take anywhere...
24 -- perhaps a custom metaclass that errors specially when fakePlayer.<property> is not found?
27 function pipeworks
.tube_item(pos
, item
)
28 -- Take item in any format
29 local stack
= ItemStack(item
)
30 local obj
= minetest
.add_entity(pos
, "pipeworks:tubed_item")
31 obj
:get_luaentity():set_item(stack
:to_string())
35 -- adding two tube functions
36 -- can_remove(pos,node,stack,dir) returns the maximum number of items of that stack that can be removed
37 -- remove_items(pos,node,stack,dir,count) removes count items and returns them
38 -- both optional w/ sensible defaults and fallback to normal allow_* function
39 -- XXX: possibly change insert_object to insert_item
41 -- sname = the current name to allow for, or nil if it allows anything
43 local function grabAndFire(frominv
,frominvname
,frompos
,fromnode
,sname
,tube
,idef
,dir
,all
)
44 for spos
,stack
in ipairs(frominv
:get_list(frominvname
)) do
45 if (sname
== nil and stack
:get_name() ~= "") or stack
:get_name() == sname
then
46 local doRemove
= stack
:get_count()
47 if tube
.can_remove
then
48 doRemove
= tube
.can_remove(frompos
, fromnode
, stack
, dir
)
49 elseif idef
.allow_metadata_inventory_take
then
50 doRemove
= idef
.allow_metadata_inventory_take(frompos
,"main",spos
, stack
, fakePlayer
)
52 -- stupid lack of continue statements grumble
57 count
= math
.min(stack
:get_count(), doRemove
)
61 if tube
.remove_items
then
62 -- it could be the entire stack...
63 item
= tube
.remove_items(frompos
, fromnode
, stack
, dir
, count
)
65 item
= stack
:take_item(count
)
66 frominv
:set_stack(frominvname
, spos
, stack
)
67 if idef
.on_metadata_inventory_take
then
68 idef
.on_metadata_inventory_take(frompos
, "main", spos
, item
, fakePlayer
)
71 local item1
= pipeworks
.tube_item(vector
.add(frompos
, vector
.multiply(dir
, 1.4)), item
)
72 item1
:get_luaentity().start_pos
= vector
.add(frompos
, dir
)
73 item1
:set_velocity(dir
)
74 item1
:set_acceleration({x
=0, y
=0, z
=0})
75 return true-- only fire one item, please
82 minetest
.register_node("pipeworks:filter", {
83 description
= "Filter",
84 tiles
= {"pipeworks_filter_top.png", "pipeworks_filter_top.png", "pipeworks_filter_output.png",
85 "pipeworks_filter_input.png", "pipeworks_filter_side.png", "pipeworks_filter_top.png"},
86 paramtype2
= "facedir",
87 groups
= {snappy
=2,choppy
=2,oddly_breakable_by_hand
=2,tubedevice
=1,mesecon
=2},
88 sounds
= hades_sounds
.node_sound_wood_defaults(),
89 on_construct
= function(pos
)
90 local meta
= minetest
.get_meta(pos
)
91 meta
:set_string("formspec",
93 "list[current_name;main;1,0;8,2;]"..
94 "list[current_player;main;0,2.5;10,4;]")
95 meta
:set_string("infotext", "Filter")
96 local inv
= meta
:get_inventory()
97 inv
:set_size("main", 10*4)
99 can_dig
= function(pos
,player
)
100 local meta
= minetest
.get_meta(pos
);
101 local inv
= meta
:get_inventory()
102 return inv
:is_empty("main")
104 after_place_node
= function(pos
)
105 pipeworks
.scan_for_tube_objects(pos
)
107 after_dig_node
= function(pos
)
108 pipeworks
.scan_for_tube_objects(pos
)
110 mesecons
={effector
={action_on
=function(pos
,node
)
111 minetest
.registered_nodes
[node
.name
].on_punch(pos
,node
,nil)
113 tube
={connect_sides
={right
=1}},
114 on_punch
= function (pos
, node
, puncher
)
115 local meta
= minetest
.get_meta(pos
);
116 local inv
= meta
:get_inventory()
117 local dir
= facedir_to_right_dir(node
.param2
)
118 local frompos
= {x
=pos
.x
- dir
.x
, y
=pos
.y
- dir
.y
, z
=pos
.z
- dir
.z
}
119 local fromnode
=minetest
.get_node(frompos
)
120 if not fromnode
then return end
121 local idef
= minetest
.registered_nodes
[fromnode
.name
]
123 local tube
= idef
.tube
124 if not (tube
and tube
.input_inventory
) then
127 if tube
.before_filter
then
128 tube
.before_filter(frompos
)
130 local frommeta
= minetest
.get_meta(frompos
)
131 local frominvname
= tube
.input_inventory
132 local frominv
= frommeta
:get_inventory()
135 for _
,filter
in ipairs(inv
:get_list("main")) do
136 sname
= filter
:get_name()
138 -- XXX: that's a lot of parameters
139 if grabAndFire(frominv
, frominvname
, frompos
, fromnode
, sname
, tube
, idef
, dir
) then
145 if not fired
and inv
:is_empty("main") then
146 grabAndFire(frominv
,frominvname
,frompos
,fromnode
,nil,tube
,idef
,dir
)
148 if tube
.after_filter
then
149 tube
.after_filter(frompos
)
154 minetest
.register_node("pipeworks:mese_filter", {
155 description
= "Mese Filter",
156 tiles
= {"pipeworks_mese_filter_top.png", "pipeworks_mese_filter_top.png", "pipeworks_mese_filter_output.png",
157 "pipeworks_mese_filter_input.png", "pipeworks_mese_filter_side.png", "pipeworks_mese_filter_top.png"},
158 paramtype2
= "facedir",
159 groups
= {snappy
=2,choppy
=2,oddly_breakable_by_hand
=2,tubedevice
=1,mesecon
=2},
160 sounds
= hades_sounds
.node_sound_wood_defaults(),
161 on_construct
= function(pos
)
162 local meta
= minetest
.get_meta(pos
)
163 meta
:set_string("formspec",
165 "list[current_name;main;1,0;8,2;]"..
166 "list[current_player;main;0,2.5;10,4;]")
167 meta
:set_string("infotext", "Mese Filter")
168 local inv
= meta
:get_inventory()
169 inv
:set_size("main", 10*4)
171 can_dig
= function(pos
,player
)
172 local meta
= minetest
.get_meta(pos
);
173 local inv
= meta
:get_inventory()
174 return inv
:is_empty("main")
176 after_place_node
= function(pos
)
177 pipeworks
.scan_for_tube_objects(pos
)
179 after_dig_node
= function(pos
)
180 pipeworks
.scan_for_tube_objects(pos
)
182 mesecons
={effector
={action_on
=function(pos
,node
)
183 minetest
.registered_nodes
[node
.name
].on_punch(pos
,node
,nil)
185 tube
={connect_sides
={right
=1}},
186 on_punch
= function (pos
, node
, puncher
)
187 local meta
= minetest
.get_meta(pos
);
188 local inv
= meta
:get_inventory()
189 local dir
= facedir_to_right_dir(node
.param2
)
190 local frompos
= {x
=pos
.x
- dir
.x
, y
=pos
.y
- dir
.y
, z
=pos
.z
- dir
.z
}
191 local fromnode
=minetest
.get_node(frompos
)
192 local idef
= minetest
.registered_nodes
[fromnode
.name
]
194 local tube
= idef
.tube
195 if not (tube
and tube
.input_inventory
) then
198 local frommeta
= minetest
.get_meta(frompos
)
199 local frominvname
= minetest
.registered_nodes
[fromnode
.name
].tube
.input_inventory
200 local frominv
= frommeta
:get_inventory()
202 for _
,filter
in ipairs(inv
:get_list("main")) do
203 sname
= filter
:get_name()
205 if grabAndFire(frominv
, frominvname
, frompos
, fromnode
, sname
, tube
, idef
, dir
, true) then return end
208 if inv
:is_empty("main") then
209 grabAndFire(frominv
, frominvname
, frompos
, fromnode
, nil, tube
, idef
, dir
, true)
214 local function roundpos(pos
)
215 return {x
=math
.floor(pos
.x
+0.5),y
=math
.floor(pos
.y
+0.5),z
=math
.floor(pos
.z
+0.5)}
218 local function addVect(pos
,vect
)
219 return {x
=pos
.x
+vect
.x
,y
=pos
.y
+vect
.y
,z
=pos
.z
+vect
.z
}
222 local adjlist
={{x
=0,y
=0,z
=1},{x
=0,y
=0,z
=-1},{x
=0,y
=1,z
=0},{x
=0,y
=-1,z
=0},{x
=1,y
=0,z
=0},{x
=-1,y
=0,z
=0}}
224 function pipeworks
.notvel(tbl
, vel
)
226 for _
,val
in ipairs(tbl
) do
227 if val
.x
~= -vel
.x
or val
.y
~= -vel
.y
or val
.z
~= -vel
.z
then table.insert(tbl2
, val
) end
232 local function go_next(pos
, velocity
, stack
)
235 local cnode
= minetest
.get_node(pos
)
236 local cmeta
= minetest
.get_meta(pos
)
239 local speed
= math
.abs(velocity
.x
+ velocity
.y
+ velocity
.z
)
240 local vel
= {x
= velocity
.x
/speed
, y
= velocity
.y
/speed
, z
= velocity
.z
/speed
,speed
=speed
}
243 elseif speed
>= 1.1 then
249 if minetest
.registered_nodes
[cnode
.name
] and minetest
.registered_nodes
[cnode
.name
].tube
and minetest
.registered_nodes
[cnode
.name
].tube
.can_go
then
250 can_go
= minetest
.registered_nodes
[cnode
.name
].tube
.can_go(pos
, cnode
, vel
, stack
)
252 can_go
= pipeworks
.notvel(adjlist
, vel
)
255 for _
,vect
in ipairs(can_go
) do
256 local npos
= addVect(pos
,vect
)
257 local node
= minetest
.get_node(npos
)
258 local tube_receiver
= minetest
.get_item_group(node
.name
,"tubedevice_receiver")
259 meta
= minetest
.get_meta(npos
)
260 local tubelike
= meta
:get_int("tubelike")
261 if tube_receiver
== 1 then
262 if minetest
.registered_nodes
[node
.name
].tube
and
263 minetest
.registered_nodes
[node
.name
].tube
.can_insert
and
264 minetest
.registered_nodes
[node
.name
].tube
.can_insert(npos
, node
, stack
, vect
) then
265 local i
= #chests
+ 1
268 chests
[i
].vect
= vect
270 elseif tubelike
== 1 then
277 if chests
[1] == nil then--no chests found
278 if tubes
[1] == nil then
281 n
= (cmeta
:get_int("tubedir")%(#tubes
)) + 1
282 if pipeworks
.enable_cyclic_mode
then
283 cmeta
:set_int("tubedir",n
)
285 velocity
.x
= tubes
[n
].vect
.x
*vel
.speed
286 velocity
.y
= tubes
[n
].vect
.y
*vel
.speed
287 velocity
.z
= tubes
[n
].vect
.z
*vel
.speed
290 n
= (cmeta
:get_int("tubedir")%(#chests
))+1
291 if pipeworks
.enable_cyclic_mode
then
292 cmeta
:set_int("tubedir",n
)
294 velocity
.x
= chests
[n
].vect
.x
*speed
295 velocity
.y
= chests
[n
].vect
.y
*speed
296 velocity
.z
= chests
[n
].vect
.z
*speed
301 minetest
.register_entity("pipeworks:tubed_item", {
302 initial_properties
= {
305 -- collisionbox = {0,0,0,0,0,0},
306 collisionbox
= {0.1,0.1,0.1,0.1,0.1,0.1},
308 visual_size
= {x
=0.5, y
=0.5},
310 spritediv
= {x
=1, y
=1},
311 initial_sprite_basepos
= {x
=0, y
=0},
318 physical_state
= false,
320 set_item
= function(self
, itemstring
)
321 self
.itemstring
= itemstring
322 local stack
= ItemStack(itemstring
)
323 local itemtable
= stack
:to_table()
326 itemname
= stack
:to_table().name
328 local item_texture
= nil
330 if minetest
.registered_items
[itemname
] then
331 item_texture
= minetest
.registered_items
[itemname
].inventory_image
332 item_type
= minetest
.registered_items
[itemname
].type
337 textures
= {"unknown_item.png"}
339 if item_texture
and item_texture
~= "" then
340 prop
.visual
= "sprite"
341 prop
.textures
= {item_texture
}
342 prop
.visual_size
= {x
=0.3, y
=0.3}
344 prop
.visual
= "wielditem"
345 prop
.textures
= {itemname
}
346 prop
.visual_size
= {x
=0.15, y
=0.15}
348 self
.object
:set_properties(prop
)
351 get_staticdata
= function(self
)
352 if self
.start_pos
==nil then return end
353 local velocity
=self
.object
:get_velocity()
354 self
.object
:set_pos(self
.start_pos
)
355 return minetest
.serialize({
356 itemstring
=self
.itemstring
,
358 start_pos
=self
.start_pos
362 on_activate
= function(self
, staticdata
)
363 if staticdata
=="" or staticdata
==nil then return end
364 local item
= minetest
.deserialize(staticdata
)
365 local stack
= ItemStack(item
.itemstring
)
366 local itemtable
= stack
:to_table()
369 itemname
= stack
:to_table().name
373 self
.start_pos
=item
.start_pos
374 self
.object
:set_velocity(item
.velocity
)
375 self
.object
:set_acceleration({x
=0, y
=0, z
=0})
376 self
.object
:set_pos(item
.start_pos
)
378 self
:set_item(item
.itemstring
)
381 on_step
= function(self
, dtime
)
382 if self
.start_pos
==nil then
383 local pos
= self
.object
:get_pos()
384 self
.start_pos
=roundpos(pos
)
386 local pos
= self
.object
:get_pos()
387 local node
= minetest
.get_node(pos
)
388 local meta
= minetest
.get_meta(pos
)
389 local tubelike
= meta
:get_int("tubelike")
390 local stack
= ItemStack(self
.itemstring
)
393 local velocity
=self
.object
:get_velocity()
395 if velocity
== nil then return end
397 local velocitycopy
= {x
= velocity
.x
, y
= velocity
.y
, z
= velocity
.z
}
400 local speed
= math
.abs(velocity
.x
+velocity
.y
+velocity
.z
)
401 local vel
= {x
= velocity
.x
/speed
, y
= velocity
.y
/speed
, z
= velocity
.z
/speed
, speed
= speed
}
403 if math
.abs(vel
.x
) == 1 then
404 local next_node
= math
.abs(pos
.x
-self
.start_pos
.x
)
405 if next_node
>= 1 then
406 self
.start_pos
.x
= self
.start_pos
.x
+vel
.x
409 elseif math
.abs(vel
.y
) == 1 then
410 local next_node
= math
.abs(pos
.y
-self
.start_pos
.y
)
411 if next_node
>= 1 then
412 self
.start_pos
.y
= self
.start_pos
.y
+vel
.y
415 elseif math
.abs(vel
.z
) == 1 then
416 local next_node
= math
.abs(pos
.z
-self
.start_pos
.z
)
417 if next_node
>= 1 then
418 self
.start_pos
.z
= self
.start_pos
.z
+vel
.z
423 local sposcopy
= {x
= self
.start_pos
.x
, y
= self
.start_pos
.y
, z
= self
.start_pos
.z
}
425 node
= minetest
.get_node(self
.start_pos
)
426 if moved
and minetest
.get_item_group(node
.name
, "tubedevice_receiver") == 1 then
428 if minetest
.registered_nodes
[node
.name
].tube
and minetest
.registered_nodes
[node
.name
].tube
.insert_object
then
429 leftover
= minetest
.registered_nodes
[node
.name
].tube
.insert_object(self
.start_pos
, node
, stack
, vel
)
433 if leftover
:is_empty() then
437 velocity
.x
= -velocity
.x
438 velocity
.y
= -velocity
.y
439 velocity
.z
= -velocity
.z
440 self
.object
:set_velocity(velocity
)
441 self
:set_item(leftover
:to_string())
446 if go_next (self
.start_pos
, velocity
, stack
) == 0 then
447 drop_pos
= minetest
.find_node_near(vector
.add(self
.start_pos
, velocity
), 1, "air")
449 minetest
.item_drop(stack
, nil, drop_pos
)
455 if velocity
.x
~=velocitycopy
.x
or velocity
.y
~=velocitycopy
.y
or velocity
.z
~=velocitycopy
.z
or
456 self
.start_pos
.x
~=sposcopy
.x
or self
.start_pos
.y
~=sposcopy
.y
or self
.start_pos
.z
~=sposcopy
.z
then
457 self
.object
:set_pos(self
.start_pos
)
458 self
.object
:set_velocity(velocity
)
463 if minetest
.get_modpath("mesecons_mvps") ~= nil then
464 mesecon
:register_mvps_unmov("pipeworks:tubed_item")
465 mesecon
:register_on_mvps_move(function(moved_nodes
)
466 local objects_to_move
= {}
467 for _
, n
in ipairs(moved_nodes
) do
468 local objects
= minetest
.get_objects_inside_radius(n
.oldpos
, 1)
469 for _
, obj
in ipairs(objects
) do
470 local entity
= obj
:get_luaentity()
471 if entity
and entity
.name
== "pipeworks:tubed_item" then
472 objects_to_move
[#objects_to_move
+1] = obj
476 if #objects_to_move
> 0 then
477 local dir
= vector
.subtract(moved_nodes
[1].pos
, moved_nodes
[1].oldpos
)
478 for _
, obj
in ipairs(objects_to_move
) do
479 local entity
= obj
:get_luaentity()
480 obj
:set_pos(vector
.add(obj
:get_pos(), dir
))
481 entity
.start_pos
= vector
.add(entity
.start_pos
, dir
)