From fa10dc93ae8c606036bf92d0da2a3557d3de4788 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 1 Feb 2018 22:45:19 +0100 Subject: [PATCH] Add _on_dispense callback for dispenser; refactor --- mods/ENTITIES/mcl_boats/init.lua | 10 + mods/ENTITIES/mcl_minecarts/init.lua | 14 ++ mods/ITEMS/REDSTONE/mcl_dispensers/init.lua | 248 ++++---------------- mods/ITEMS/mcl_buckets/init.lua | 60 ++++- mods/ITEMS/mcl_chests/init.lua | 12 + mods/ITEMS/mcl_dye/init.lua | 14 ++ mods/ITEMS/mcl_fire/fire_charge.lua | 11 + mods/ITEMS/mcl_fire/flint_and_steel.lua | 15 ++ mods/ITEMS/mcl_throwing/arrow.lua | 6 + mods/ITEMS/mcl_throwing/throwable.lua | 10 +- mods/ITEMS/mcl_tnt/init.lua | 7 + 11 files changed, 196 insertions(+), 211 deletions(-) diff --git a/mods/ENTITIES/mcl_boats/init.lua b/mods/ENTITIES/mcl_boats/init.lua index e03beac879..b4138ee816 100644 --- a/mods/ENTITIES/mcl_boats/init.lua +++ b/mods/ENTITIES/mcl_boats/init.lua @@ -307,6 +307,16 @@ for b=1, #boat_ids do end return itemstack 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] diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index 848e555668..e7a1ef06e1 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -332,6 +332,7 @@ mcl_minecarts.place_minecart = function(itemstack, pointed_thing) return itemstack end + local register_craftitem = function(itemstring, entity_id, description, longdesc, usagehelp, icon, creative) 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) 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, } def.description = description diff --git a/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua b/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua index b3256e94cf..26759ab328 100644 --- a/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua @@ -94,197 +94,19 @@ local dispenserdef = { if #stacks >= 1 then local r = math.random(1, #stacks) 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 stackdef = stack:get_definition() local iname = stack:get_name() 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 ]===] - 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() - inv:set_stack("main", stack_id, stack) + -- Hardcoded dispensions -- - elseif iname == "mcl_throwing:egg" or iname == "mcl_throwing:snowball" then - -- Throw egg or snowball - 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 + -- Armor, mob heads and pumpkins + if igroups.armor_head or igroups.armor_torso or igroups.armor_legs or igroups.armor_feet then local armor_type, armor_slot local armor_dispensed = false if igroups.armor_head then @@ -373,19 +195,9 @@ local dispenserdef = { end end - elseif igroups.shulker_box then - -- 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 - + -- Spawn Egg elseif igroups.spawn_egg then - -- Place spawn egg + -- Spawn mob if not dropnodedef.walkable then pointed_thing = { above = droppos, under = { x=droppos.x, y=droppos.y-1, z=droppos.z } } minetest.add_entity(droppos, stack:get_name()) @@ -394,14 +206,44 @@ local dispenserdef = { inv:set_stack("main", stack_id, stack) end - -- TODO: Many other dispenser actions - else - -- Drop item - minetest.add_item(droppos, dropitem) - - stack:take_item() - inv:set_stack("main", stack_id, stack) + -- 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 end + + end end, rules = mesecon.rules.alldirs, diff --git a/mods/ITEMS/mcl_buckets/init.lua b/mods/ITEMS/mcl_buckets/init.lua index 2a8142fce1..43260abab8 100644 --- a/mods/ITEMS/mcl_buckets/init.lua +++ b/mods/ITEMS/mcl_buckets/init.lua @@ -37,6 +37,12 @@ local sound_take = function(itemname, pos) 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 -- source_place = a string or function. -- * string: name of the node to place @@ -88,12 +94,6 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent 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 if type(source_place) == "function" then node_place = source_place(place_pos) @@ -154,7 +154,29 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent else return 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 @@ -234,6 +256,30 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { 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 diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index f8a0815cb6..e17dcd5978 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -689,6 +689,18 @@ for color, desc in pairs(boxtypes) do local inv = meta:get_inventory() inv:set_size("main", 9*3) 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) local nmeta = minetest.get_meta(pos) local ninv = nmeta:get_inventory() diff --git a/mods/ITEMS/mcl_dye/init.lua b/mods/ITEMS/mcl_dye/init.lua index c69befce62..1c78cbaedc 100644 --- a/mods/ITEMS/mcl_dye/init.lua +++ b/mods/ITEMS/mcl_dye/init.lua @@ -300,6 +300,20 @@ minetest.register_craftitem("mcl_dye:white", { end return itemstack 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", { diff --git a/mods/ITEMS/mcl_fire/fire_charge.lua b/mods/ITEMS/mcl_fire/fire_charge.lua index 5cf25b774b..144d195907 100644 --- a/mods/ITEMS/mcl_fire/fire_charge.lua +++ b/mods/ITEMS/mcl_fire/fire_charge.lua @@ -32,6 +32,17 @@ minetest.register_craftitem("mcl_fire:fire_charge", { end return itemstack 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({ diff --git a/mods/ITEMS/mcl_fire/flint_and_steel.lua b/mods/ITEMS/mcl_fire/flint_and_steel.lua index c835a1321a..d074f31af5 100644 --- a/mods/ITEMS/mcl_fire/flint_and_steel.lua +++ b/mods/ITEMS/mcl_fire/flint_and_steel.lua @@ -42,6 +42,21 @@ minetest.register_tool("mcl_fire:flint_and_steel", { end return itemstack 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" }, }) diff --git a/mods/ITEMS/mcl_throwing/arrow.lua b/mods/ITEMS/mcl_throwing/arrow.lua index 0bf12375bd..32eae870b0 100644 --- a/mods/ITEMS/mcl_throwing/arrow.lua +++ b/mods/ITEMS/mcl_throwing/arrow.lua @@ -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.", inventory_image = "mcl_throwing_arrow_inv.png", 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", { diff --git a/mods/ITEMS/mcl_throwing/throwable.lua b/mods/ITEMS/mcl_throwing/throwable.lua index 047b072d6f..64efc8f93b 100644 --- a/mods/ITEMS/mcl_throwing/throwable.lua +++ b/mods/ITEMS/mcl_throwing/throwable.lua @@ -34,7 +34,7 @@ end -- Throw item local throw_function = function(entity_name, velocity) local func = function(item, player, pointed_thing) - local playerpos = player:getpos() + local playerpos = player:get_pos() 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) obj:get_luaentity()._thrower = player:get_player_name() @@ -46,6 +46,12 @@ local throw_function = function(entity_name, velocity) return func 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 local get_staticdata = function(self) local data = { @@ -288,6 +294,7 @@ minetest.register_craftitem("mcl_throwing:snowball", { inventory_image = "mcl_throwing_snowball.png", stack_max = 16, on_use = throw_function("mcl_throwing:snowball_entity"), + _on_dispense = dispense_function, }) -- Egg @@ -298,6 +305,7 @@ minetest.register_craftitem("mcl_throwing:egg", { inventory_image = "mcl_throwing_egg.png", stack_max = 16, on_use = throw_function("mcl_throwing:egg_entity"), + _on_dispense = dispense_function, groups = { craftitem = 1 }, }) diff --git a/mods/ITEMS/mcl_tnt/init.lua b/mods/ITEMS/mcl_tnt/init.lua index ce2bfef0aa..777ea3559c 100644 --- a/mods/ITEMS/mcl_tnt/init.lua +++ b/mods/ITEMS/mcl_tnt/init.lua @@ -76,6 +76,13 @@ minetest.register_node("mcl_tnt:tnt", { tnt.ignite(pointed_thing.under) return true 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, })