2017-02-14 03:23:06 +01:00
--[[ This mod registers 3 nodes:
- One node for the horizontal - facing dispensers ( mcl_dispensers : dispenser )
- One node for the upwards - facing dispensers ( mcl_dispenser : dispenser_up )
- One node for the downwards - facing dispensers ( mcl_dispenser : dispenser_down )
3 node definitions are needed because of the way the textures are defined .
All node definitions share a lot of code , so this is the reason why there
are so many weird tables below .
] ]
-- For after_place_node
local setup_dispenser = function ( pos )
-- Set formspec and inventory
local form = " size[9,8.75] " ..
" background[-0.19,-0.25;9.41,9.49;crafting_inventory_9_slots.png] " ..
2017-02-17 23:06:52 +01:00
mcl_vars.inventory_header ..
2017-02-14 03:23:06 +01:00
" image[3,-0.2;5,0.75;mcl_dispensers_fnt_dispenser.png] " ..
" list[current_player;main;0,4.5;9,3;9] " ..
" list[current_player;main;0,7.74;9,1;] " ..
" list[current_name;main;3,0.5;3,3;] " ..
" listring[current_name;main] " ..
" listring[current_player;main] "
local meta = minetest.get_meta ( pos )
meta : set_string ( " formspec " , form )
local inv = meta : get_inventory ( )
inv : set_size ( " main " , 9 )
end
2018-01-11 01:28:36 +01:00
local orientate_dispenser = function ( pos , placer )
-- Not placed by player
if not placer then return end
-- Pitch in degrees
local pitch = placer : get_look_vertical ( ) * ( 180 / math.pi )
local node = minetest.get_node ( pos )
if pitch > 55 then
2018-01-13 03:15:32 +01:00
minetest.swap_node ( pos , { name = " mcl_dispensers:dispenser_up " , param2 = node.param2 } )
2018-01-11 01:28:36 +01:00
elseif pitch < - 55 then
2018-01-13 03:15:32 +01:00
minetest.swap_node ( pos , { name = " mcl_dispensers:dispenser_down " , param2 = node.param2 } )
2018-01-11 01:28:36 +01:00
end
end
2017-12-05 14:09:39 +01:00
local on_rotate
if minetest.get_modpath ( " screwdriver " ) then
on_rotate = screwdriver.rotate_simple
end
2017-02-14 03:23:06 +01:00
-- Shared core definition table
local dispenserdef = {
is_ground_content = false ,
sounds = mcl_sounds.node_sound_stone_defaults ( ) ,
2019-02-08 21:59:01 +01:00
allow_metadata_inventory_move = function ( pos , from_list , from_index , to_list , to_index , count , player )
local name = player : get_player_name ( )
if minetest.is_protected ( pos , name ) then
minetest.record_protection_violation ( pos , name )
return 0
else
return count
end
end ,
allow_metadata_inventory_take = function ( pos , listname , index , stack , player )
local name = player : get_player_name ( )
if minetest.is_protected ( pos , name ) then
minetest.record_protection_violation ( pos , name )
return 0
else
return stack : get_count ( )
end
end ,
allow_metadata_inventory_put = function ( pos , listname , index , stack , player )
local name = player : get_player_name ( )
if minetest.is_protected ( pos , name ) then
minetest.record_protection_violation ( pos , name )
return 0
else
return stack : get_count ( )
end
end ,
2017-02-14 03:23:06 +01:00
after_dig_node = function ( pos , oldnode , oldmetadata , digger )
local meta = minetest.get_meta ( pos )
local meta2 = meta
meta : from_table ( oldmetadata )
local inv = meta : get_inventory ( )
for i = 1 , inv : get_size ( " main " ) do
local stack = inv : get_stack ( " main " , i )
if not stack : is_empty ( ) then
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 }
minetest.add_item ( p , stack )
end
end
meta : from_table ( meta2 : to_table ( ) )
end ,
2017-02-27 01:52:24 +01:00
_mcl_blast_resistance = 17.5 ,
_mcl_hardness = 3.5 ,
2017-02-14 03:23:06 +01:00
mesecons = { effector = {
-- Dispense random item when triggered
action_on = function ( pos , node )
local meta = minetest.get_meta ( pos )
local inv = meta : get_inventory ( )
2017-02-14 22:04:37 +01:00
local droppos , dropdir
2017-02-14 03:23:06 +01:00
if node.name == " mcl_dispensers:dispenser " then
2017-02-14 22:04:37 +01:00
dropdir = vector.multiply ( minetest.facedir_to_dir ( node.param2 ) , - 1 )
2017-02-15 00:16:47 +01:00
droppos = vector.add ( pos , dropdir )
2017-02-14 03:23:06 +01:00
elseif node.name == " mcl_dispensers:dispenser_up " then
2017-02-14 22:04:37 +01:00
dropdir = { x = 0 , y = 1 , z = 0 }
2017-02-14 03:23:06 +01:00
droppos = { x = pos.x , y = pos.y + 1 , z = pos.z }
elseif node.name == " mcl_dispensers:dispenser_down " then
2017-02-14 22:04:37 +01:00
dropdir = { x = 0 , y =- 1 , z = 0 }
2017-02-14 03:23:06 +01:00
droppos = { x = pos.x , y = pos.y - 1 , z = pos.z }
end
local dropnode = minetest.get_node ( droppos )
local dropnodedef = minetest.registered_nodes [ dropnode.name ]
local stacks = { }
for i = 1 , inv : get_size ( " main " ) do
local stack = inv : get_stack ( " main " , i )
if not stack : is_empty ( ) then
table.insert ( stacks , { stack = stack , stackpos = i } )
end
end
if # stacks >= 1 then
local r = math.random ( 1 , # stacks )
local stack = stacks [ r ] . stack
2018-02-01 22:45:19 +01:00
local dropitem = ItemStack ( stack )
dropitem : set_count ( 1 )
2017-02-14 03:23:06 +01:00
local stack_id = stacks [ r ] . stackpos
2018-02-01 22:45:19 +01:00
local stackdef = stack : get_definition ( )
2017-02-14 03:23:06 +01:00
local iname = stack : get_name ( )
local igroups = minetest.registered_items [ iname ] . groups
--[===[ Dispense item ]===]
2018-02-01 22:45:19 +01:00
-- Hardcoded dispensions --
2017-02-14 03:53:50 +01:00
2018-02-01 22:45:19 +01:00
-- Armor, mob heads and pumpkins
if igroups.armor_head or igroups.armor_torso or igroups.armor_legs or igroups.armor_feet then
2017-02-14 19:45:02 +01:00
local armor_type , armor_slot
2017-06-11 22:53:12 +02:00
local armor_dispensed = false
2017-02-14 19:45:02 +01:00
if igroups.armor_head then
armor_type = " armor_head "
armor_slot = 2
elseif igroups.armor_torso then
armor_type = " armor_torso "
armor_slot = 3
elseif igroups.armor_legs then
armor_type = " armor_legs "
armor_slot = 4
elseif igroups.armor_feet then
armor_type = " armor_feet "
armor_slot = 5
end
local droppos_below = { x = droppos.x , y = droppos.y - 1 , z = droppos.z }
local dropnode_below = minetest.get_node ( droppos_below )
-- Put armor on player or armor stand
local standpos
if dropnode.name == " 3d_armor_stand:armor_stand " then
standpos = droppos
elseif dropnode_below.name == " 3d_armor_stand:armor_stand " then
standpos = droppos_below
end
if standpos then
local dropmeta = minetest.get_meta ( standpos )
local dropinv = dropmeta : get_inventory ( )
if dropinv : room_for_item ( armor_type , dropitem ) then
dropinv : add_item ( armor_type , dropitem )
--[[ FIXME: For some reason, this function is not called after calling add_item,
so we call it manually to update the armor stand entity .
This may need investigation and the following line may be a small hack . ] ]
minetest.registered_nodes [ " 3d_armor_stand:armor_stand " ] . on_metadata_inventory_put ( standpos )
stack : take_item ( )
inv : set_stack ( " main " , stack_id , stack )
2017-06-11 22:53:12 +02:00
armor_dispensed = true
2017-02-14 19:45:02 +01:00
end
else
-- Put armor on nearby player
-- First search for player in front of dispenser (check 2 nodes)
local objs1 = minetest.get_objects_inside_radius ( droppos , 1 )
local objs2 = minetest.get_objects_inside_radius ( droppos_below , 1 )
local objs_table = { objs1 , objs2 }
local player
for oi = 1 , # objs_table do
local objs_inner = objs_table [ oi ]
for o = 1 , # objs_inner do
--[[ First player in list is the lucky one. The other player get nothing :-(
If multiple players are close to the dispenser , it can be a bit
-- unpredictable on who gets the armor. ]]
if objs_inner [ o ] : is_player ( ) then
player = objs_inner [ o ]
break
end
end
if player then
break
end
end
-- If player found, add armor
if player then
local ainv = minetest.get_inventory ( { type = " detached " , name = player : get_player_name ( ) .. " _armor " } )
local pinv = player : get_inventory ( )
if ainv : get_stack ( " armor " , armor_slot ) : is_empty ( ) and pinv : get_stack ( " armor " , armor_slot ) : is_empty ( ) then
ainv : set_stack ( " armor " , armor_slot , dropitem )
pinv : set_stack ( " armor " , armor_slot , dropitem )
armor : set_player_armor ( player )
armor : update_inventory ( player )
stack : take_item ( )
inv : set_stack ( " main " , stack_id , stack )
2017-06-11 22:53:12 +02:00
armor_dispensed = true
2017-02-14 19:45:02 +01:00
end
end
2017-06-11 22:53:12 +02:00
-- Place head or pumpkin as node, if equipping it as armor has failed
if not armor_dispensed then
if igroups.head or iname == " mcl_farming:pumpkin_face " then
if dropnodedef.buildable_to then
minetest.set_node ( droppos , { name = iname , param2 = node.param2 } )
stack : take_item ( )
inv : set_stack ( " main " , stack_id , stack )
end
end
end
end
2018-02-01 22:45:19 +01:00
-- Spawn Egg
2017-02-15 00:31:00 +01:00
elseif igroups.spawn_egg then
2018-02-01 22:45:19 +01:00
-- Spawn mob
2017-02-15 00:31:00 +01:00
if not dropnodedef.walkable then
pointed_thing = { above = droppos , under = { x = droppos.x , y = droppos.y - 1 , z = droppos.z } }
2018-01-27 03:55:59 +01:00
minetest.add_entity ( droppos , stack : get_name ( ) )
2017-02-15 00:31:00 +01:00
stack : take_item ( )
inv : set_stack ( " main " , stack_id , stack )
end
2018-02-01 22:45:19 +01:00
-- Generalized dispension
elseif ( not dropnodedef.walkable or stackdef._dispense_into_walkable ) then
--[[ _on_dispense(stack, pos, droppos, dropnode, dropdir)
* stack : Itemstack which is dispense
* pos : Position of dispenser
* droppos : Position to which to dispense item
* dropnode : Node of droppos
* dropdir : Drop direction
_dispense_into_walkable : If true , can dispense into walkable nodes
] ]
if stackdef._on_dispense then
-- Item-specific dispension (if defined)
local od_ret = stackdef._on_dispense ( dropitem , pos , droppos , dropnode , dropdir )
if od_ret then
local newcount = stack : get_count ( ) - 1
stack : set_count ( newcount )
inv : set_stack ( " main " , stack_id , stack )
if newcount == 0 then
inv : set_stack ( " main " , stack_id , od_ret )
elseif inv : room_for_item ( " main " , od_ret ) then
inv : add_item ( " main " , od_ret )
else
minetest.add_item ( droppos , dropitem )
end
else
stack : take_item ( )
inv : set_stack ( " main " , stack_id , stack )
end
else
-- Drop item otherwise
minetest.add_item ( droppos , dropitem )
stack : take_item ( )
inv : set_stack ( " main " , stack_id , stack )
end
2017-02-14 03:23:06 +01:00
end
2018-02-01 22:45:19 +01:00
2017-02-14 03:23:06 +01:00
end
2017-09-14 02:20:47 +02:00
end ,
rules = mesecon.rules . alldirs ,
2017-12-05 14:09:39 +01:00
} } ,
on_rotate = on_rotate ,
2017-02-14 03:23:06 +01:00
}
-- Horizontal dispenser
local horizontal_def = table.copy ( dispenserdef )
horizontal_def.description = " Dispenser "
2017-03-11 02:50:12 +01:00
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. "
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 .
The dispenser will do different things , depending on the dispensed item :
• Arrows : Are launched
• Eggs and snowballs : Are thrown
• Fire charges : Are fired in a straight line
• Armor : Will be equipped to players and armor stands
• Boats : Are placed on water or are dropped
• Minecart : Are placed on rails or are dropped
• Bone meal : Is applied on the block it is facint
• Empty buckets : Are used to collect a liquid source
• Filled buckets : Are used to place a liquid source
2017-06-11 22:54:46 +02:00
• Heads , pumpkins : Equipped to players and armor stands , or placed as a block
• Shulker boxes : Are placed as a block
2017-03-11 02:50:12 +01:00
• TNT : Is placed and ignited
• Flint and steel : Is used to ignite a fire in air and to ignite TNT
• Spawn eggs : Will summon the mob they contain
• Other items : Are simply dropped ] ]
2017-02-14 03:23:06 +01:00
horizontal_def.after_place_node = function ( pos , placer , itemstack , pointed_thing )
setup_dispenser ( pos )
2018-01-11 01:28:36 +01:00
orientate_dispenser ( pos , placer )
2017-02-14 03:23:06 +01:00
end
horizontal_def.tiles = {
" default_furnace_top.png " , " default_furnace_bottom.png " ,
" default_furnace_side.png " , " default_furnace_side.png " ,
" default_furnace_side.png " , " mcl_dispensers_dispenser_front_horizontal.png "
}
horizontal_def.paramtype2 = " facedir "
2017-03-11 05:34:58 +01:00
horizontal_def.groups = { pickaxey = 1 , container = 2 , material_stone = 1 }
2017-02-14 03:23:06 +01:00
minetest.register_node ( " mcl_dispensers:dispenser " , horizontal_def )
-- Down dispenser
local down_def = table.copy ( dispenserdef )
down_def.description = " Downwards-Facing Dispenser "
down_def.after_place_node = setup_dispenser
down_def.tiles = {
" default_furnace_top.png " , " mcl_dispensers_dispenser_front_vertical.png " ,
" default_furnace_side.png " , " default_furnace_side.png " ,
" default_furnace_side.png " , " default_furnace_side.png "
}
2017-03-11 05:34:58 +01:00
down_def.groups = { pickaxey = 1 , container = 2 , not_in_creative_inventory = 1 , material_stone = 1 }
2017-03-02 19:53:53 +01:00
down_def._doc_items_create_entry = false
2017-02-14 03:23:06 +01:00
down_def.drop = " mcl_dispensers:dispenser "
minetest.register_node ( " mcl_dispensers:dispenser_down " , down_def )
-- Up dispenser
-- The up dispenser is almost identical to the down dispenser , it only differs in textures
2017-08-02 01:34:12 +02:00
local up_def = table.copy ( down_def )
2017-02-14 03:23:06 +01:00
up_def.description = " Upwards-Facing Dispenser "
up_def.tiles = {
" mcl_dispensers_dispenser_front_vertical.png " , " default_furnace_bottom.png " ,
" default_furnace_side.png " , " default_furnace_side.png " ,
" default_furnace_side.png " , " default_furnace_side.png "
}
minetest.register_node ( " mcl_dispensers:dispenser_up " , up_def )
minetest.register_craft ( {
output = ' mcl_dispensers:dispenser ' ,
recipe = {
{ " mcl_core:cobble " , " mcl_core:cobble " , " mcl_core:cobble " , } ,
2018-05-07 23:10:49 +02:00
{ " mcl_core:cobble " , " mcl_bows:bow " , " mcl_core:cobble " , } ,
2017-02-14 03:23:06 +01:00
{ " mcl_core:cobble " , " mesecons:redstone " , " mcl_core:cobble " , } ,
}
} )
2017-02-14 04:39:37 +01:00
2017-03-21 04:27:50 +01:00
-- Add entry aliases for the Help
if minetest.get_modpath ( " doc " ) then
doc.add_entry_alias ( " nodes " , " mcl_dispensers:dispenser " , " nodes " , " mcl_dispensers:dispenser_down " )
doc.add_entry_alias ( " nodes " , " mcl_dispensers:dispenser " , " nodes " , " mcl_dispensers:dispenser_up " )
end