Add _on_dispense callback for dispenser; refactor

Wuzzy 2018-02-01 22:45:19 +01:00
parent 8774e7674d
commit fa10dc93ae
11 changed files with 196 additions and 211 deletions

@ -307,6 +307,16 @@ for b=1, #boat_ids do
end end
return itemstack return itemstack
end, end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
local below = {x=droppos.x, y=droppos.y-1, z=droppos.z}
local belownode = minetest.get_node(below)
-- Place boat as entity on or in water
if minetest.get_item_group(dropnode.name, "water") ~= 0 or (dropnode.name == "air" and minetest.get_item_group(belownode.name, "water") ~= 0) then
minetest.add_entity(droppos, "mcl_boats:boat")
else
minetest.add_item(droppos, stack)
end
end,
}) })
local c = craftstuffs[b] local c = craftstuffs[b]

@ -332,6 +332,7 @@ mcl_minecarts.place_minecart = function(itemstack, pointed_thing)
return itemstack return itemstack
end end
local register_craftitem = function(itemstring, entity_id, description, longdesc, usagehelp, icon, creative) local register_craftitem = function(itemstring, entity_id, description, longdesc, usagehelp, icon, creative)
entity_mapping[itemstring] = entity_id entity_mapping[itemstring] = entity_id
@ -356,6 +357,19 @@ local register_craftitem = function(itemstring, entity_id, description, longdesc
return mcl_minecarts.place_minecart(itemstack, pointed_thing) return mcl_minecarts.place_minecart(itemstack, pointed_thing)
end, end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Place minecart as entity on rail. If there's no rail, just drop it.
local placed
if minetest.get_item_group(dropnode.name, "rail") ~= 0 then
-- FIXME: This places minecarts even if the spot is already occupied
local pointed_thing = { under = droppos, above = { x=droppos.x, y=droppos.y+1, z=droppos.z } }
placed = mcl_minecarts.place_minecart(stack, pointed_thing)
end
if placed == nil then
-- Drop item
minetest.add_item(droppos, stack)
end
end,
groups = groups, groups = groups,
} }
def.description = description def.description = description

@ -94,197 +94,19 @@ local dispenserdef = {
if #stacks >= 1 then if #stacks >= 1 then
local r = math.random(1, #stacks) local r = math.random(1, #stacks)
local stack = stacks[r].stack local stack = stacks[r].stack
local dropitem = ItemStack(stack:get_name()) local dropitem = ItemStack(stack)
dropitem:set_count(1)
local stack_id = stacks[r].stackpos local stack_id = stacks[r].stackpos
local stackdef = stack:get_definition()
local iname = stack:get_name() local iname = stack:get_name()
local igroups = minetest.registered_items[iname].groups local igroups = minetest.registered_items[iname].groups
-- Do not dispense into solid nodes. Exception: Water bucket into cauldron
if dropnodedef.walkable and not (minetest.get_item_group(dropnode.name, "cauldron") ~= 0 and (iname == "mcl_buckets:bucket_water" or iname == "mcl_buckets:bucket_river_water")) then
-- no-op
--[===[ Dispense item ]===] --[===[ Dispense item ]===]
elseif iname == "mcl_throwing:arrow" then
-- Shoot arrow
local shootpos = vector.add(pos, vector.multiply(dropdir, 0.51))
local yaw = math.atan2(dropdir.z, dropdir.x) - math.pi/2
mcl_throwing.shoot_arrow(iname, shootpos, dropdir, yaw, nil, 19, 3)
stack:take_item() -- Hardcoded dispensions --
inv:set_stack("main", stack_id, stack)
elseif iname == "mcl_throwing:egg" or iname == "mcl_throwing:snowball" then -- Armor, mob heads and pumpkins
-- Throw egg or snowball if igroups.armor_head or igroups.armor_torso or igroups.armor_legs or igroups.armor_feet then
local shootpos = vector.add(pos, vector.multiply(dropdir, 0.51))
mcl_throwing.throw(iname, shootpos, dropdir)
stack:take_item()
inv:set_stack("main", stack_id, stack)
elseif iname == "mcl_fire:fire_charge" then
-- Throw fire charge
local shootpos = vector.add(pos, vector.multiply(dropdir, 0.51))
local fireball = minetest.add_entity(shootpos, "mobs_mc:blaze_fireball")
local ent = fireball:get_luaentity()
ent._shot_from_dispenser = true
local v = ent.velocity or 1
fireball:setvelocity(vector.multiply(dropdir, v))
ent.switch = 1
stack:take_item()
inv:set_stack("main", stack_id, stack)
elseif iname == "mcl_fire:flint_and_steel" then
-- Ignite air or fire
if dropnode.name == "air" then
minetest.add_node(droppos, {name="mcl_fire:fire"})
if not minetest.settings:get_bool("creative_mode") then
stack:add_wear(65535/65) -- 65 uses
end
elseif dropnode.name == "mcl_tnt:tnt" then
tnt.ignite(droppos)
if not minetest.settings:get_bool("creative_mode") then
stack:add_wear(65535/65) -- 65 uses
end
end
inv:set_stack("main", stack_id, stack)
elseif iname == "mcl_tnt:tnt" then
-- Place and ignite TNT
if dropnodedef.buildable_to then
minetest.set_node(droppos, {name = iname})
tnt.ignite(droppos)
stack:take_item()
inv:set_stack("main", stack_id, stack)
end
elseif iname == "mcl_buckets:bucket_empty" then
-- Fill empty bucket with liquid or drop bucket if no liquid
local collect_liquid = false
local bucket_id
if dropnode.name == "mcl_core:water_source" then
collect_liquid = true
bucket_id = "mcl_buckets:bucket_water"
elseif dropnode.name == "mcl_core:lava_source" or dropnode.name == "mcl_nether:nether_lava_source" then
collect_liquid = true
bucket_id = "mcl_buckets:bucket_lava"
elseif dropnode.name == "mclx_core:river_water_source" then
collect_liquid = true
bucket_id = "mcl_buckets:bucket_river_water"
end
if collect_liquid then
minetest.set_node(droppos, {name="air"})
-- Fill bucket with liquid and put it back into inventory
-- if there's still space. If not, drop it.
stack:take_item()
inv:set_stack("main", stack_id, stack)
local new_bucket = ItemStack(bucket_id)
if inv:room_for_item("main", new_bucket) then
inv:add_item("main", new_bucket)
else
minetest.add_item(droppos, dropitem)
end
else
-- No liquid found: Drop empty bucket
minetest.add_item(droppos, dropitem)
stack:take_item()
inv:set_stack("main", stack_id, stack)
end
elseif iname == "mcl_buckets:bucket_water" or iname == "mcl_buckets:bucket_river_water" or iname == "mcl_buckets:bucket_lava" then
local do_empty = false
-- Place water/lava source
if minetest.get_item_group(dropnode.name, "cauldron") ~= 0 then
if iname == "mcl_buckets:bucket_water" then
minetest.set_node(droppos, {name = "mcl_cauldrons:cauldron_3"})
do_empty = true
elseif iname == "mcl_buckets:bucket_river_water" then
minetest.set_node(droppos, {name = "mcl_cauldrons:cauldron_3r"})
do_empty = true
end
elseif dropnodedef.buildable_to then
local dim = mcl_worlds.pos_to_dimension(droppos)
if iname == "mcl_buckets:bucket_water" then
if dim == "nether" then
minetest.sound_play("fire_extinguish_flame", {pos = droppos, gain = 0.25, max_hear_distance = 16})
else
minetest.set_node(droppos, {name = "mcl_core:water_source"})
end
do_empty = true
elseif iname == "mcl_buckets:bucket_river_water" then
if dim == "nether" then
minetest.sound_play("fire_extinguish_flame", {pos = droppos, gain = 0.25, max_hear_distance = 16})
else
minetest.set_node(droppos, {name = "mclx_core:river_water_source"})
end
do_empty = true
elseif iname == "mcl_buckets:bucket_lava" then
if dim == "nether" then
minetest.set_node(droppos, {name = "mcl_nether:nether_lava_source"})
else
minetest.set_node(droppos, {name = "mcl_core:lava_source"})
end
do_empty = true
end
end
if do_empty then
stack:take_item()
inv:set_stack("main", stack_id, stack)
if inv:room_for_item("main", "mcl_buckets:bucket_empty") then
inv:add_item("main", "mcl_buckets:bucket_empty")
else
minetest.add_item(droppos, dropitem)
end
end
elseif iname == "mcl_dye:white" then
-- Apply bone meal, if possible
local pointed_thing
if dropnode.name == "air" then
pointed_thing = { above = droppos, under = { x=droppos.x, y=droppos.y-1, z=droppos.z } }
else
pointed_thing = { above = pos, under = droppos }
end
local success = mcl_dye.apply_bone_meal(pointed_thing)
if success then
stack:take_item()
inv:set_stack("main", stack_id, stack)
end
elseif minetest.get_item_group(iname, "minecart") == 1 then
-- Place minecart as entity on rail
local placed
if dropnodedef.groups.rail then
-- FIXME: This places minecarts even if the spot is already occupied
local pointed_thing = { under = droppos, above = { x=droppos.x, y=droppos.y+1, z=droppos.z } }
placed = mcl_minecarts.place_minecart(stack, pointed_thing)
end
if placed == nil then
-- Drop item
minetest.add_item(droppos, dropitem)
end
stack:take_item()
inv:set_stack("main", stack_id, stack)
elseif igroups.boat then
local below = {x=droppos.x, y=droppos.y-1, z=droppos.z}
local belownode = minetest.get_node(below)
-- Place boat as entity on or in water
if dropnodedef.groups.water or (dropnode.name == "air" and minetest.registered_nodes[belownode.name].groups.water) then
minetest.add_entity(droppos, "mcl_boats:boat")
else
minetest.add_item(droppos, dropitem)
end
stack:take_item()
inv:set_stack("main", stack_id, stack)
elseif igroups.armor_head or igroups.armor_torso or igroups.armor_legs or igroups.armor_feet then
local armor_type, armor_slot local armor_type, armor_slot
local armor_dispensed = false local armor_dispensed = false
if igroups.armor_head then if igroups.armor_head then
@ -373,19 +195,9 @@ local dispenserdef = {
end end
end end
elseif igroups.shulker_box then -- Spawn Egg
-- Place shulker box as node
if dropnodedef.buildable_to then
minetest.set_node(droppos, {name = iname, param2 = node.param2})
local imeta = stack:get_metadata()
local iinv_main = minetest.deserialize(imeta)
local ninv = minetest.get_inventory({type="node", pos=droppos})
ninv:set_list("main", iinv_main)
stack:take_item()
end
elseif igroups.spawn_egg then elseif igroups.spawn_egg then
-- Place spawn egg -- Spawn mob
if not dropnodedef.walkable then if not dropnodedef.walkable then
pointed_thing = { above = droppos, under = { x=droppos.x, y=droppos.y-1, z=droppos.z } } pointed_thing = { above = droppos, under = { x=droppos.x, y=droppos.y-1, z=droppos.z } }
minetest.add_entity(droppos, stack:get_name()) minetest.add_entity(droppos, stack:get_name())
@ -394,14 +206,44 @@ local dispenserdef = {
inv:set_stack("main", stack_id, stack) inv:set_stack("main", stack_id, stack)
end end
-- TODO: Many other dispenser actions -- Generalized dispension
else elseif (not dropnodedef.walkable or stackdef._dispense_into_walkable) then
-- Drop item --[[ _on_dispense(stack, pos, droppos, dropnode, dropdir)
minetest.add_item(droppos, dropitem) * stack: Itemstack which is dispense
* pos: Position of dispenser
stack:take_item() * droppos: Position to which to dispense item
inv:set_stack("main", stack_id, stack) * 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
end end
end end
end, end,
rules = mesecon.rules.alldirs, rules = mesecon.rules.alldirs,

@ -37,6 +37,12 @@ local sound_take = function(itemname, pos)
end end
end end
local place_liquid = function(pos, itemstring)
local fullness = minetest.registered_nodes[itemstring].liquid_range
sound_place(itemstring, pos)
minetest.add_node(pos, {name=itemstring, param2=fullness})
end
-- Register a new liquid -- Register a new liquid
-- source_place = a string or function. -- source_place = a string or function.
-- * string: name of the node to place -- * string: name of the node to place
@ -88,12 +94,6 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent
end end
end end
local place_liquid = function(pos, itemstring)
local fullness = minetest.registered_nodes[itemstring].liquid_range
sound_place(itemstring, pos)
minetest.add_node(pos, {name=itemstring, param2=fullness})
end
local node_place local node_place
if type(source_place) == "function" then if type(source_place) == "function" then
node_place = source_place(place_pos) node_place = source_place(place_pos)
@ -154,7 +154,29 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent
else else
return return
end end
end end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
local iname = stack:get_name()
local buildable = minetest.registered_nodes[dropnode.name].buildable_to
if extra_check and extra_check(droppos) == false then
-- Fail placement of liquid
elseif buildable then
-- buildable; replace the node
if minetest.is_protected(droppos, "") then
return stack
end
local node_place
if type(source_place) == "function" then
node_place = source_place(droppos)
else
node_place = source_place
end
place_liquid(droppos, node_place)
stack:set_name("mcl_buckets:bucket_empty")
end
return stack
end,
}) })
end end
end end
@ -234,6 +256,30 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", {
end end
end end
end, end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Fill empty bucket with liquid or drop bucket if no liquid
local collect_liquid = false
local liquiddef = mcl_buckets.liquids[dropnode.name]
local new_bucket
if liquiddef ~= nil and liquiddef.itemname ~= nil and (dropnode.name == liquiddef.source_take) then
-- Fill bucket
new_bucket = ItemStack({name = liquiddef.itemname, metadata = tostring(dropnode.param2)})
sound_take(dropnode.name, droppos)
collect_liquid = true
end
if collect_liquid then
minetest.set_node(droppos, {name="air"})
-- Fill bucket with liquid
stack = new_bucket
else
-- No liquid found: Drop empty bucket
minetest.add_item(droppos, stack)
stack:take_item()
end
return stack
end,
}) })
if mod_mcl_core then if mod_mcl_core then

@ -689,6 +689,18 @@ for color, desc in pairs(boxtypes) do
local inv = meta:get_inventory() local inv = meta:get_inventory()
inv:set_size("main", 9*3) inv:set_size("main", 9*3)
end, end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Place shulker box as node
if minetest.registered_nodes[dropnode.name].buildable_to then
minetest.set_node(droppos, {name = stack:get_name(), param2 = minetest.dir_to_facedir(dropdir)})
local imeta = stack:get_metadata()
local iinv_main = minetest.deserialize(imeta)
local ninv = minetest.get_inventory({type="node", pos=droppos})
ninv:set_list("main", iinv_main)
stack:take_item()
end
return stack
end,
after_place_node = function(pos, placer, itemstack, pointed_thing) after_place_node = function(pos, placer, itemstack, pointed_thing)
local nmeta = minetest.get_meta(pos) local nmeta = minetest.get_meta(pos)
local ninv = nmeta:get_inventory() local ninv = nmeta:get_inventory()

@ -300,6 +300,20 @@ minetest.register_craftitem("mcl_dye:white", {
end end
return itemstack return itemstack
end, end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Apply bone meal, if possible
local pointed_thing
if dropnode.name == "air" then
pointed_thing = { above = droppos, under = { x=droppos.x, y=droppos.y-1, z=droppos.z } }
else
pointed_thing = { above = pos, under = droppos }
end
local success = mcl_dye.apply_bone_meal(pointed_thing)
if success then
stack:take_item()
end
return stack
end,
}) })
minetest.register_craftitem("mcl_dye:brown", { minetest.register_craftitem("mcl_dye:brown", {

@ -32,6 +32,17 @@ minetest.register_craftitem("mcl_fire:fire_charge", {
end end
return itemstack return itemstack
end, end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Throw fire charge
local shootpos = vector.add(pos, vector.multiply(dropdir, 0.51))
local fireball = minetest.add_entity(shootpos, "mobs_mc:blaze_fireball")
local ent = fireball:get_luaentity()
ent._shot_from_dispenser = true
local v = ent.velocity or 1
fireball:setvelocity(vector.multiply(dropdir, v))
ent.switch = 1
stack:take_item()
end,
}) })
minetest.register_craft({ minetest.register_craft({

@ -42,6 +42,21 @@ minetest.register_tool("mcl_fire:flint_and_steel", {
end end
return itemstack return itemstack
end, end,
_dispense_into_walkable = true,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
if dropnode.name == "air" then
minetest.add_node(droppos, {name="mcl_fire:fire"})
if not minetest.settings:get_bool("creative_mode") then
stack:add_wear(65535/65) -- 65 uses
end
elseif dropnode.name == "mcl_tnt:tnt" then
tnt.ignite(droppos)
if not minetest.settings:get_bool("creative_mode") then
stack:add_wear(65535/65) -- 65 uses
end
end
return stack
end,
sound = { breaks = "default_tool_breaks" }, sound = { breaks = "default_tool_breaks" },
}) })

@ -7,6 +7,12 @@ minetest.register_craftitem("mcl_throwing:arrow", {
_doc_items_usagehelp = "To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory.", _doc_items_usagehelp = "To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory.",
inventory_image = "mcl_throwing_arrow_inv.png", inventory_image = "mcl_throwing_arrow_inv.png",
groups = { ammo=1, ammo_bow=1 }, groups = { ammo=1, ammo_bow=1 },
_on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir)
-- Shoot arrow
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
local yaw = math.atan2(dropdir.z, dropdir.x) - math.pi/2
mcl_throwing.shoot_arrow(itemstack:get_name(), shootpos, dropdir, yaw, nil, 19, 3)
end,
}) })
minetest.register_node("mcl_throwing:arrow_box", { minetest.register_node("mcl_throwing:arrow_box", {

@ -34,7 +34,7 @@ end
-- Throw item -- Throw item
local throw_function = function(entity_name, velocity) local throw_function = function(entity_name, velocity)
local func = function(item, player, pointed_thing) local func = function(item, player, pointed_thing)
local playerpos = player:getpos() local playerpos = player:get_pos()
local dir = player:get_look_dir() local dir = player:get_look_dir()
local obj = mcl_throwing.throw(item, {x=playerpos.x, y=playerpos.y+1.5, z=playerpos.z}, dir, velocity) local obj = mcl_throwing.throw(item, {x=playerpos.x, y=playerpos.y+1.5, z=playerpos.z}, dir, velocity)
obj:get_luaentity()._thrower = player:get_player_name() obj:get_luaentity()._thrower = player:get_player_name()
@ -46,6 +46,12 @@ local throw_function = function(entity_name, velocity)
return func return func
end end
local dispense_function = function(stack, dispenserpos, droppos, dropnode, dropdir)
-- Launch throwable item
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
mcl_throwing.throw(stack:get_name(), shootpos, dropdir)
end
-- Staticdata handling because objects may want to be reloaded -- Staticdata handling because objects may want to be reloaded
local get_staticdata = function(self) local get_staticdata = function(self)
local data = { local data = {
@ -288,6 +294,7 @@ minetest.register_craftitem("mcl_throwing:snowball", {
inventory_image = "mcl_throwing_snowball.png", inventory_image = "mcl_throwing_snowball.png",
stack_max = 16, stack_max = 16,
on_use = throw_function("mcl_throwing:snowball_entity"), on_use = throw_function("mcl_throwing:snowball_entity"),
_on_dispense = dispense_function,
}) })
-- Egg -- Egg
@ -298,6 +305,7 @@ minetest.register_craftitem("mcl_throwing:egg", {
inventory_image = "mcl_throwing_egg.png", inventory_image = "mcl_throwing_egg.png",
stack_max = 16, stack_max = 16,
on_use = throw_function("mcl_throwing:egg_entity"), on_use = throw_function("mcl_throwing:egg_entity"),
_on_dispense = dispense_function,
groups = { craftitem = 1 }, groups = { craftitem = 1 },
}) })

@ -76,6 +76,13 @@ minetest.register_node("mcl_tnt:tnt", {
tnt.ignite(pointed_thing.under) tnt.ignite(pointed_thing.under)
return true return true
end, end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Place and ignite TNT
if minetest.registered_nodes[dropnode.name].buildable_to then
minetest.set_node(droppos, {name = stack:get_name()})
tnt.ignite(droppos)
end
end,
sounds = sounds, sounds = sounds,
}) })