2017-02-14 02:23:06 +00: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 .
] ]
2019-03-08 00:07:41 +00:00
local S = minetest.get_translator ( " mcl_dispensers " )
2017-02-14 02:23:06 +00:00
-- For after_place_node
local setup_dispenser = function ( pos )
-- Set formspec and inventory
local form = " size[9,8.75] " ..
2021-04-19 12:44:20 +00:00
" label[0,4.0; " .. minetest.formspec_escape ( minetest.colorize ( " #313131 " , S ( " Inventory " ) ) ) .. " ] " ..
2017-02-14 02:23:06 +00:00
" list[current_player;main;0,4.5;9,3;9] " ..
2020-03-29 12:15:00 +00:00
mcl_formspec.get_itemslot_bg ( 0 , 4.5 , 9 , 3 ) ..
2017-02-14 02:23:06 +00:00
" list[current_player;main;0,7.74;9,1;] " ..
2020-03-29 12:15:00 +00:00
mcl_formspec.get_itemslot_bg ( 0 , 7.74 , 9 , 1 ) ..
2021-04-19 12:44:20 +00:00
" label[3,0; " .. minetest.formspec_escape ( minetest.colorize ( " #313131 " , S ( " Dispenser " ) ) ) .. " ] " ..
2017-02-14 02:23:06 +00:00
" list[current_name;main;3,0.5;3,3;] " ..
2020-03-29 12:15:00 +00:00
mcl_formspec.get_itemslot_bg ( 3 , 0.5 , 3 , 3 ) ..
2017-02-14 02:23:06 +00:00
" 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 00:28:36 +00: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 02:15:32 +00:00
minetest.swap_node ( pos , { name = " mcl_dispensers:dispenser_up " , param2 = node.param2 } )
2018-01-11 00:28:36 +00:00
elseif pitch < - 55 then
2018-01-13 02:15:32 +00:00
minetest.swap_node ( pos , { name = " mcl_dispensers:dispenser_down " , param2 = node.param2 } )
2018-01-11 00:28:36 +00:00
end
end
2017-12-05 13:09:39 +00:00
local on_rotate
if minetest.get_modpath ( " screwdriver " ) then
on_rotate = screwdriver.rotate_simple
end
2017-02-14 02:23:06 +00:00
-- Shared core definition table
local dispenserdef = {
is_ground_content = false ,
sounds = mcl_sounds.node_sound_stone_defaults ( ) ,
2019-02-08 20:59:01 +00: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 02:23:06 +00: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 ,
2020-04-17 19:40:13 +00:00
_mcl_blast_resistance = 3.5 ,
2017-02-27 00:52:24 +00:00
_mcl_hardness = 3.5 ,
2017-02-14 02:23:06 +00: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 21:04:37 +00:00
local droppos , dropdir
2017-02-14 02:23:06 +00:00
if node.name == " mcl_dispensers:dispenser " then
2017-02-14 21:04:37 +00:00
dropdir = vector.multiply ( minetest.facedir_to_dir ( node.param2 ) , - 1 )
2017-02-14 23:16:47 +00:00
droppos = vector.add ( pos , dropdir )
2017-02-14 02:23:06 +00:00
elseif node.name == " mcl_dispensers:dispenser_up " then
2017-02-14 21:04:37 +00:00
dropdir = { x = 0 , y = 1 , z = 0 }
2017-02-14 02:23:06 +00:00
droppos = { x = pos.x , y = pos.y + 1 , z = pos.z }
elseif node.name == " mcl_dispensers:dispenser_down " then
2017-02-14 21:04:37 +00:00
dropdir = { x = 0 , y =- 1 , z = 0 }
2017-02-14 02:23:06 +00: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 21:45:19 +00:00
local dropitem = ItemStack ( stack )
dropitem : set_count ( 1 )
2017-02-14 02:23:06 +00:00
local stack_id = stacks [ r ] . stackpos
2018-02-01 21:45:19 +00:00
local stackdef = stack : get_definition ( )
2017-02-14 02:23:06 +00:00
local iname = stack : get_name ( )
local igroups = minetest.registered_items [ iname ] . groups
--[===[ Dispense item ]===]
2018-02-01 21:45:19 +00:00
-- Hardcoded dispensions --
2017-02-14 02:53:50 +00:00
2018-02-01 21:45:19 +00:00
-- Armor, mob heads and pumpkins
2021-04-22 11:51:36 +00:00
if igroups.armor then
local droppos_below = { x = droppos.x , y = droppos.y - 1 , z = droppos.z }
2017-02-14 18:45:02 +00:00
2021-04-22 11:51:36 +00:00
for _ , objs in ipairs ( { minetest.get_objects_inside_radius ( droppos , 1 ) , minetest.get_objects_inside_radius ( droppos_below , 1 ) } ) do
for _ , obj in ipairs ( objs ) do
stack = mcl_armor.equip ( stack , obj )
if stack : is_empty ( ) then
2017-02-14 18:45:02 +00:00
break
end
end
2021-04-22 11:51:36 +00:00
if stack : is_empty ( ) then
break
2017-02-14 18:45:02 +00:00
end
2021-04-22 11:51:36 +00:00
end
2017-06-11 20:53:12 +00:00
-- Place head or pumpkin as node, if equipping it as armor has failed
2021-04-22 11:51:36 +00:00
if not stack : is_empty ( ) 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 ( )
2017-06-11 20:53:12 +00:00
end
end
end
2021-04-22 11:51:36 +00:00
inv : set_stack ( " main " , stack_id , stack )
2018-02-01 21:45:19 +00:00
-- Spawn Egg
2017-02-14 23:31:00 +00:00
elseif igroups.spawn_egg then
2018-02-01 21:45:19 +00:00
-- Spawn mob
2017-02-14 23:31:00 +00:00
if not dropnodedef.walkable then
pointed_thing = { above = droppos , under = { x = droppos.x , y = droppos.y - 1 , z = droppos.z } }
2018-01-27 02:55:59 +00:00
minetest.add_entity ( droppos , stack : get_name ( ) )
2017-02-14 23:31:00 +00:00
stack : take_item ( )
inv : set_stack ( " main " , stack_id , stack )
end
2018-02-01 21:45:19 +00: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 02:23:06 +00:00
end
2018-02-01 21:45:19 +00:00
2017-02-14 02:23:06 +00:00
end
2017-09-14 00:20:47 +00:00
end ,
rules = mesecon.rules . alldirs ,
2017-12-05 13:09:39 +00:00
} } ,
on_rotate = on_rotate ,
2017-02-14 02:23:06 +00:00
}
-- Horizontal dispenser
local horizontal_def = table.copy ( dispenserdef )
2019-03-08 00:07:41 +00:00
horizontal_def.description = S ( " Dispenser " )
2020-03-12 00:35:11 +00:00
horizontal_def._tt_help = S ( " 9 inventory slots " ) .. " \n " .. S ( " Launches item when powered by redstone power " )
2019-03-08 00:07:41 +00:00
horizontal_def._doc_items_longdesc = S ( " 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. " )
2019-03-16 01:00:48 +00:00
horizontal_def._doc_items_usagehelp = S ( " Place the dispenser in one of 6 possible directions. The “hole” is where items will fly out of the dispenser. Use the dispenser to access its inventory. Insert the items you wish to dispense. Supply the dispenser with redstone energy once to dispense a random item. " ) .. " \n \n " ..
2017-03-11 01:50:12 +00:00
2019-03-08 00:07:41 +00:00
S ( " The dispenser will do different things, depending on the dispensed item: " ) .. " \n \n " ..
2017-03-11 01:50:12 +00:00
2019-03-16 01:00:48 +00:00
S ( " • Arrows: Are launched " ) .. " \n " ..
S ( " • Eggs and snowballs: Are thrown " ) .. " \n " ..
S ( " • Fire charges: Are fired in a straight line " ) .. " \n " ..
S ( " • Armor: Will be equipped to players and armor stands " ) .. " \n " ..
S ( " • Boats: Are placed on water or are dropped " ) .. " \n " ..
S ( " • Minecart: Are placed on rails or are dropped " ) .. " \n " ..
S ( " • Bone meal: Is applied on the block it is facing " ) .. " \n " ..
S ( " • Empty buckets: Are used to collect a liquid source " ) .. " \n " ..
S ( " • Filled buckets: Are used to place a liquid source " ) .. " \n " ..
S ( " • Heads, pumpkins: Equipped to players and armor stands, or placed as a block " ) .. " \n " ..
S ( " • Shulker boxes: Are placed as a block " ) .. " \n " ..
S ( " • TNT: Is placed and ignited " ) .. " \n " ..
S ( " • Flint and steel: Is used to ignite a fire in air and to ignite TNT " ) .. " \n " ..
S ( " • Spawn eggs: Will summon the mob they contain " ) .. " \n " ..
S ( " • Other items: Are simply dropped " )
2017-03-11 01:50:12 +00:00
2017-02-14 02:23:06 +00:00
horizontal_def.after_place_node = function ( pos , placer , itemstack , pointed_thing )
setup_dispenser ( pos )
2018-01-11 00:28:36 +00:00
orientate_dispenser ( pos , placer )
2017-02-14 02:23:06 +00: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 04:34:58 +00:00
horizontal_def.groups = { pickaxey = 1 , container = 2 , material_stone = 1 }
2017-02-14 02:23:06 +00:00
minetest.register_node ( " mcl_dispensers:dispenser " , horizontal_def )
-- Down dispenser
local down_def = table.copy ( dispenserdef )
2019-03-08 00:07:41 +00:00
down_def.description = S ( " Downwards-Facing Dispenser " )
2017-02-14 02:23:06 +00:00
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 04:34:58 +00:00
down_def.groups = { pickaxey = 1 , container = 2 , not_in_creative_inventory = 1 , material_stone = 1 }
2017-03-02 18:53:53 +00:00
down_def._doc_items_create_entry = false
2017-02-14 02:23:06 +00: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-01 23:34:12 +00:00
local up_def = table.copy ( down_def )
2019-03-08 00:07:41 +00:00
up_def.description = S ( " Upwards-Facing Dispenser " )
2017-02-14 02:23:06 +00:00
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 21:10:49 +00:00
{ " mcl_core:cobble " , " mcl_bows:bow " , " mcl_core:cobble " , } ,
2017-02-14 02:23:06 +00:00
{ " mcl_core:cobble " , " mesecons:redstone " , " mcl_core:cobble " , } ,
}
} )
2017-02-14 03:39:37 +00:00
2017-03-21 03:27:50 +00: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
2019-03-21 15:08:29 +00:00
2020-03-29 12:35:01 +00:00
-- Legacy
2019-03-21 15:08:29 +00:00
minetest.register_lbm ( {
2020-03-29 12:35:01 +00:00
label = " Update dispenser formspecs (0.60.0) " ,
name = " mcl_dispensers:update_formspecs_0_60_0 " ,
2019-03-21 15:08:29 +00:00
nodenames = { " mcl_dispensers:dispenser " , " mcl_dispensers:dispenser_down " , " mcl_dispensers:dispenser_up " } ,
action = function ( pos , node )
setup_dispenser ( pos )
minetest.log ( " action " , " [mcl_dispenser] Node formspec updated at " .. minetest.pos_to_string ( pos ) )
end ,
} )