1 --[[ This mod registers 3 nodes:
2 - One node for the horizontal-facing dispensers (mcl_dispensers:dispenser)
3 - One node for the upwards-facing dispensers (mcl_dispenser:dispenser_up)
4 - One node for the downwards-facing dispensers (mcl_dispenser:dispenser_down)
6 3 node definitions are needed because of the way the textures are defined.
7 All node definitions share a lot of code, so this is the reason why there
8 are so many weird tables below.
11 -- For after_place_node
12 local setup_dispenser
= function(pos
)
13 -- Set formspec and inventory
14 local form
= "size[9,8.75]"..
15 "background[-0.19,-0.25;9.41,9.49;crafting_inventory_9_slots.png]"..
16 mcl_vars
.inventory_header
..
17 "image[3,-0.2;5,0.75;mcl_dispensers_fnt_dispenser.png]"..
18 "list[current_player;main;0,4.5;9,3;9]"..
19 "list[current_player;main;0,7.74;9,1;]"..
20 "list[current_name;main;3,0.5;3,3;]"..
21 "listring[current_name;main]"..
22 "listring[current_player;main]"
23 local meta
= minetest
.get_meta(pos
)
24 meta
:set_string("formspec", form
)
25 local inv
= meta
:get_inventory()
26 inv
:set_size("main", 9)
29 local orientate_dispenser
= function(pos
, placer
)
30 -- Not placed by player
31 if not placer
then return end
34 local pitch
= placer
:get_look_vertical() * (180 / math
.pi
)
36 local node
= minetest
.get_node(pos
)
38 minetest
.swap_node(pos
, {name
="mcl_dispensers:dispenser_up", param2
= node
.param2
})
39 elseif pitch
< -55 then
40 minetest
.swap_node(pos
, {name
="mcl_dispensers:dispenser_down", param2
= node
.param2
})
45 if minetest
.get_modpath("screwdriver") then
46 on_rotate
= screwdriver
.rotate_simple
49 -- Shared core definition table
50 local dispenserdef
= {
51 is_ground_content
= false,
52 sounds
= mcl_sounds
.node_sound_stone_defaults(),
53 after_dig_node
= function(pos
, oldnode
, oldmetadata
, digger
)
54 local meta
= minetest
.get_meta(pos
)
56 meta
:from_table(oldmetadata
)
57 local inv
= meta
:get_inventory()
58 for i
=1, inv
:get_size("main") do
59 local stack
= inv
:get_stack("main", i
)
60 if not stack
:is_empty() then
61 local p
= {x
=pos
.x
+math
.random(0, 10)/10-0.5, y
=pos
.y
, z
=pos
.z
+math
.random(0, 10)/10-0.5}
62 minetest
.add_item(p
, stack
)
65 meta
:from_table(meta2
:to_table())
67 _mcl_blast_resistance
= 17.5,
69 mesecons
= {effector
= {
70 -- Dispense random item when triggered
71 action_on
= function (pos
, node
)
72 local meta
= minetest
.get_meta(pos
)
73 local inv
= meta
:get_inventory()
74 local droppos
, dropdir
75 if node
.name
== "mcl_dispensers:dispenser" then
76 dropdir
= vector
.multiply(minetest
.facedir_to_dir(node
.param2
), -1)
77 droppos
= vector
.add(pos
, dropdir
)
78 elseif node
.name
== "mcl_dispensers:dispenser_up" then
79 dropdir
= {x
=0, y
=1, z
=0}
80 droppos
= {x
=pos
.x
, y
=pos
.y
+1, z
=pos
.z
}
81 elseif node
.name
== "mcl_dispensers:dispenser_down" then
82 dropdir
= {x
=0, y
=-1, z
=0}
83 droppos
= {x
=pos
.x
, y
=pos
.y
-1, z
=pos
.z
}
85 local dropnode
= minetest
.get_node(droppos
)
86 local dropnodedef
= minetest
.registered_nodes
[dropnode
.name
]
88 for i
=1,inv
:get_size("main") do
89 local stack
= inv
:get_stack("main", i
)
90 if not stack
:is_empty() then
91 table.insert(stacks
, {stack
= stack
, stackpos
= i
})
95 local r
= math
.random(1, #stacks
)
96 local stack
= stacks
[r
].stack
97 local dropitem
= ItemStack(stack
)
99 local stack_id
= stacks
[r
].stackpos
100 local stackdef
= stack
:get_definition()
101 local iname
= stack
:get_name()
102 local igroups
= minetest
.registered_items
[iname
].groups
104 --[===[ Dispense item ]===]
106 -- Hardcoded dispensions --
108 -- Armor, mob heads and pumpkins
109 if igroups
.armor_head
or igroups
.armor_torso
or igroups
.armor_legs
or igroups
.armor_feet
then
110 local armor_type
, armor_slot
111 local armor_dispensed
= false
112 if igroups
.armor_head
then
113 armor_type
= "armor_head"
115 elseif igroups
.armor_torso
then
116 armor_type
= "armor_torso"
118 elseif igroups
.armor_legs
then
119 armor_type
= "armor_legs"
121 elseif igroups
.armor_feet
then
122 armor_type
= "armor_feet"
126 local droppos_below
= {x
=droppos
.x
, y
=droppos
.y
-1, z
=droppos
.z
}
127 local dropnode_below
= minetest
.get_node(droppos_below
)
128 -- Put armor on player or armor stand
130 if dropnode
.name
== "3d_armor_stand:armor_stand" then
132 elseif dropnode_below
.name
== "3d_armor_stand:armor_stand" then
133 standpos
= droppos_below
136 local dropmeta
= minetest
.get_meta(standpos
)
137 local dropinv
= dropmeta
:get_inventory()
138 if dropinv
:room_for_item(armor_type
, dropitem
) then
139 dropinv
:add_item(armor_type
, dropitem
)
140 --[[ FIXME: For some reason, this function is not called after calling add_item,
141 so we call it manually to update the armor stand entity.
142 This may need investigation and the following line may be a small hack. ]]
143 minetest
.registered_nodes
["3d_armor_stand:armor_stand"].on_metadata_inventory_put(standpos
)
145 inv
:set_stack("main", stack_id
, stack
)
146 armor_dispensed
= true
149 -- Put armor on nearby player
150 -- First search for player in front of dispenser (check 2 nodes)
151 local objs1
= minetest
.get_objects_inside_radius(droppos
, 1)
152 local objs2
= minetest
.get_objects_inside_radius(droppos_below
, 1)
153 local objs_table
= {objs1
, objs2
}
155 for oi
=1, #objs_table
do
156 local objs_inner
= objs_table
[oi
]
157 for o
=1, #objs_inner
do
158 --[[ First player in list is the lucky one. The other player get nothing :-(
159 If multiple players are close to the dispenser, it can be a bit
160 -- unpredictable on who gets the armor. ]]
161 if objs_inner
[o
]:is_player() then
162 player
= objs_inner
[o
]
170 -- If player found, add armor
172 local ainv
= minetest
.get_inventory({type="detached", name
=player
:get_player_name().."_armor"})
173 local pinv
= player
:get_inventory()
174 if ainv
:get_stack("armor", armor_slot
):is_empty() and pinv
:get_stack("armor", armor_slot
):is_empty() then
175 ainv
:set_stack("armor", armor_slot
, dropitem
)
176 pinv
:set_stack("armor", armor_slot
, dropitem
)
177 armor
:set_player_armor(player
)
178 armor
:update_inventory(player
)
181 inv
:set_stack("main", stack_id
, stack
)
182 armor_dispensed
= true
186 -- Place head or pumpkin as node, if equipping it as armor has failed
187 if not armor_dispensed
then
188 if igroups
.head
or iname
== "mcl_farming:pumpkin_face" then
189 if dropnodedef
.buildable_to
then
190 minetest
.set_node(droppos
, {name
= iname
, param2
= node
.param2
})
192 inv
:set_stack("main", stack_id
, stack
)
199 elseif igroups
.spawn_egg
then
201 if not dropnodedef
.walkable
then
202 pointed_thing
= { above
= droppos
, under
= { x
=droppos
.x
, y
=droppos
.y
-1, z
=droppos
.z
} }
203 minetest
.add_entity(droppos
, stack
:get_name())
206 inv
:set_stack("main", stack_id
, stack
)
209 -- Generalized dispension
210 elseif (not dropnodedef
.walkable
or stackdef
._dispense_into_walkable
) then
211 --[[ _on_dispense(stack, pos, droppos, dropnode, dropdir)
212 * stack: Itemstack which is dispense
213 * pos: Position of dispenser
214 * droppos: Position to which to dispense item
215 * dropnode: Node of droppos
216 * dropdir: Drop direction
218 _dispense_into_walkable: If true, can dispense into walkable nodes
220 if stackdef
._on_dispense
then
221 -- Item-specific dispension (if defined)
222 local od_ret
= stackdef
._on_dispense(dropitem
, pos
, droppos
, dropnode
, dropdir
)
224 local newcount
= stack
:get_count() - 1
225 stack
:set_count(newcount
)
226 inv
:set_stack("main", stack_id
, stack
)
227 if newcount
== 0 then
228 inv
:set_stack("main", stack_id
, od_ret
)
229 elseif inv
:room_for_item("main", od_ret
) then
230 inv
:add_item("main", od_ret
)
232 minetest
.add_item(droppos
, dropitem
)
236 inv
:set_stack("main", stack_id
, stack
)
239 -- Drop item otherwise
240 minetest
.add_item(droppos
, dropitem
)
242 inv
:set_stack("main", stack_id
, stack
)
249 rules
= mesecon
.rules
.alldirs
,
251 on_rotate
= on_rotate
,
254 -- Horizontal dispenser
256 local horizontal_def
= table.copy(dispenserdef
)
257 horizontal_def
.description
= "Dispenser"
258 horizontal_def
._doc_items_longdesc
= "A dispenser is a block which acts as a redstone component which, when powered with redstone power, dispenses an item. It has a container with 9 inventory slots."
259 horizontal_def
._doc_items_usagehelp
= [[Place the dispenser in one of 6 possible directions. The “hole” is where items will fly out of the dispenser. Rightclick the dispenser to access its inventory. Insert the items you wish to dispense. Supply the dispenser with redstone energy once to dispense a single random item.
261 The dispenser will do different things, depending on the dispensed item:
263 • Arrows: Are launched
264 • Eggs and snowballs: Are thrown
265 • Fire charges: Are fired in a straight line
266 • Armor: Will be equipped to players and armor stands
267 • Boats: Are placed on water or are dropped
268 • Minecart: Are placed on rails or are dropped
269 • Bone meal: Is applied on the block it is facint
270 • Empty buckets: Are used to collect a liquid source
271 • Filled buckets: Are used to place a liquid source
272 • Heads, pumpkins: Equipped to players and armor stands, or placed as a block
273 • Shulker boxes: Are placed as a block
274 • TNT: Is placed and ignited
275 • Flint and steel: Is used to ignite a fire in air and to ignite TNT
276 • Spawn eggs: Will summon the mob they contain
277 • Other items: Are simply dropped]]
279 horizontal_def
.after_place_node
= function(pos
, placer
, itemstack
, pointed_thing
)
281 orientate_dispenser(pos
, placer
)
283 horizontal_def
.tiles
= {
284 "default_furnace_top.png", "default_furnace_bottom.png",
285 "default_furnace_side.png", "default_furnace_side.png",
286 "default_furnace_side.png", "mcl_dispensers_dispenser_front_horizontal.png"
288 horizontal_def
.paramtype2
= "facedir"
289 horizontal_def
.groups
= {pickaxey
=1, container
=2, material_stone
=1}
291 minetest
.register_node("mcl_dispensers:dispenser", horizontal_def
)
294 local down_def
= table.copy(dispenserdef
)
295 down_def
.description
= "Downwards-Facing Dispenser"
296 down_def
.after_place_node
= setup_dispenser
298 "default_furnace_top.png", "mcl_dispensers_dispenser_front_vertical.png",
299 "default_furnace_side.png", "default_furnace_side.png",
300 "default_furnace_side.png", "default_furnace_side.png"
302 down_def
.groups
= {pickaxey
=1, container
=2,not_in_creative_inventory
=1, material_stone
=1}
303 down_def
._doc_items_create_entry
= false
304 down_def
.drop
= "mcl_dispensers:dispenser"
305 minetest
.register_node("mcl_dispensers:dispenser_down", down_def
)
308 -- The up dispenser is almost identical to the down dispenser , it only differs in textures
309 local up_def
= table.copy(down_def
)
310 up_def
.description
= "Upwards-Facing Dispenser"
312 "mcl_dispensers_dispenser_front_vertical.png", "default_furnace_bottom.png",
313 "default_furnace_side.png", "default_furnace_side.png",
314 "default_furnace_side.png", "default_furnace_side.png"
316 minetest
.register_node("mcl_dispensers:dispenser_up", up_def
)
319 minetest
.register_craft({
320 output
= 'mcl_dispensers:dispenser',
322 {"mcl_core:cobble", "mcl_core:cobble", "mcl_core:cobble",},
323 {"mcl_core:cobble", "mcl_bows:bow", "mcl_core:cobble",},
324 {"mcl_core:cobble", "mesecons:redstone", "mcl_core:cobble",},
328 -- Add entry aliases for the Help
329 if minetest
.get_modpath("doc") then
330 doc
.add_entry_alias("nodes", "mcl_dispensers:dispenser", "nodes", "mcl_dispensers:dispenser_down")
331 doc
.add_entry_alias("nodes", "mcl_dispensers:dispenser", "nodes", "mcl_dispensers:dispenser_up")