diff --git a/README.md b/README.md index 7136f76..3fa0895 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ developed by [PilzAdam](https://github.com/PilzAdam/item_drop). * Left and Right keys combined (`LeftAndRight`) * Right mouse button (`RMB`) * Sneak key and right mouse button combined (`SneakAndRMB`) - * If `item_drop.pickup_keyinvert` is `true` (false by default), items are + * If `item_drop.pickup_keyinvert` is `true`, items are collected when the key is not pressed instead of when it's pressed. * Displays a particle of the picked item above the player if `item_drop.pickup_particle` is `true` (true by default) diff --git a/description.txt b/description.txt index 4488941..ef32f14 100644 --- a/description.txt +++ b/description.txt @@ -1 +1 @@ -This mod adds Minecraft like drop/pick up of items to Minetest. +A highly configurable mod providing item magnet and in-world node drops diff --git a/init.lua b/init.lua index 2d74adc..7f90680 100644 --- a/init.lua +++ b/init.lua @@ -23,27 +23,41 @@ item_drop = { end, } -if minetest.settings:get_bool("item_drop.enable_item_pickup") ~= false and -minetest.settings:get_bool("enable_item_pickup") ~= false then - local pickup_gain = tonumber( - minetest.settings:get("item_drop.pickup_sound_gain")) or - tonumber(minetest.settings:get("item_pickup_gain")) or 0.2 +local function legacy_setting_getbool(name_new, name_old, default) + local v = minetest.settings:get_bool(name_new) + if v == nil then + v = minetest.settings:get_bool(name_new) + end + if default then + return v ~= false + end + return v +end + +local function legacy_setting_getnumber(name_new, name_old, default) + return tonumber(minetest.settings:get(name_new)) + or tonumber(minetest.settings:get(name_old)) + or default +end + +if legacy_setting_getbool("item_drop.enable_item_pickup", + "enable_item_pickup", true) then + local pickup_gain = legacy_setting_getnumber("item_drop.pickup_sound_gain", + "item_pickup_gain", 0.2) local pickup_particle = - minetest.settings:get_bool("item_drop.pickup_particle") ~= false - local pickup_radius = tonumber( - minetest.settings:get("item_drop.pickup_radius")) or - tonumber(minetest.settings:get("item_pickup_radius")) or 0.75 + minetest.settings:get_bool("item_drop.pickup_particle", true) + local pickup_radius = legacy_setting_getnumber("item_drop.pickup_radius", + "item_pickup_radius", 0.75) local magnet_radius = tonumber( minetest.settings:get("item_drop.magnet_radius")) or -1 local magnet_time = tonumber( minetest.settings:get("item_drop.magnet_time")) or 5.0 local pickup_age = tonumber( minetest.settings:get("item_drop.pickup_age")) or 0.5 - local key_triggered = minetest.settings:get_bool( - "item_drop.enable_pickup_key") or - minetest.settings:get_bool("enable_item_pickup_key") ~= false + local key_triggered = legacy_setting_getbool("item_drop.enable_pickup_key", + "enable_item_pickup_key", true) local key_invert = minetest.settings:get_bool( - "item_drop.pickup_keyinvert") or false + "item_drop.pickup_keyinvert") ~= false local keytype if key_triggered then keytype = minetest.settings:get("item_drop.pickup_keytype") or @@ -131,7 +145,7 @@ minetest.settings:get_bool("enable_item_pickup") ~= false then if zero_velocity_mode then function opt_get_ent(object) if object:is_player() - or not vector.equals(object:getvelocity(), {x=0, y=0, z=0}) then + or not vector.equals(object:get_velocity(), {x=0, y=0, z=0}) then return end local ent = object:get_luaentity() @@ -246,7 +260,7 @@ minetest.settings:get_bool("enable_item_pickup") ~= false then return end - local pos = player:getpos() + local pos = player:get_pos() pos.y = pos.y+0.5 local inv @@ -270,7 +284,7 @@ minetest.settings:get_bool("enable_item_pickup") ~= false then local flying_item local pos2 if magnet_mode then - pos2 = object:getpos() + pos2 = object:get_pos() flying_item = vector.distance(pos, pos2) > pickup_radius end if not flying_item then @@ -314,45 +328,84 @@ minetest.settings:get_bool("enable_item_pickup") ~= false then minetest.after(3.0, pickup_step) end -if minetest.settings:get_bool("item_drop.enable_item_drop") ~= false and -minetest.settings:get_bool("enable_item_drop") ~= false +if legacy_setting_getbool("item_drop.enable_item_drop", "enable_item_drop", true) and not minetest.settings:get_bool("creative_mode") then - function minetest.handle_node_drops(pos, drops) + -- Workaround to test if an item metadata (ItemStackMetaRef) is empty + local function itemmeta_is_empty(meta) + local t = meta:to_table() + for k, v in pairs(t) do + if k ~= "fields" then + return false + end + assert(type(v) == "table") + if next(v) ~= nil then + return false + end + end + return true + end + + -- Tests if the item has special information such as metadata + local function can_split_item(item) + return item:get_wear() == 0 and itemmeta_is_empty(item:get_meta()) + end + + local function spawn_items(pos, items_to_spawn) + for i = 1,#items_to_spawn do + local obj = minetest.add_item(pos, items_to_spawn[i]) + if not obj then + error("Couldn't spawn item " .. name .. ", drops: " + .. dump(drops)) + end + + local vel = obj:get_velocity() + local x = math.random(-5, 4) + if x >= 0 then + x = x+1 + end + vel.x = 1 / x + local z = math.random(-5, 4) + if z >= 0 then + z = z+1 + end + vel.z = 1 / z + obj:set_velocity(vel) + end + end + + local old_handle_node_drops = minetest.handle_node_drops + function minetest.handle_node_drops(pos, drops, player) + if player.is_fake_player then + -- Node Breaker or similar machines should receive items in the + -- inventory + return old_handle_node_drops(pos, drops, player) + end for i = 1,#drops do local item = drops[i] - local count, name if type(item) == "string" then - count = 1 - name = item - else - count = item:get_count() - name = item:get_name() + -- The string is not necessarily only the item name, + -- so always convert it to ItemStack + item = ItemStack(item) end + local count = item:get_count() + local name = item:get_name() -- Sometimes nothing should be dropped if name == "" - or not minetest.registered_nodes[name] then + or not minetest.registered_items[name] then count = 0 end - for _ = 1,count do - local obj = minetest.add_item(pos, name) - if not obj then - error("Couldn't spawn item " .. name .. ", drops: " .. dump(drops)) + if count > 0 then + -- Split items if possible + local items_to_spawn = {item} + if can_split_item(item) then + for i = 1,count do + items_to_spawn[i] = name + end end - local vel = obj:getvelocity() - local x = math.random(-5, 4) - if x >= 0 then - x = x+1 - end - vel.x = 1 / x - local z = math.random(-5, 4) - if z >= 0 then - z = z+1 - end - vel.z = 1 / z - obj:set_velocity(vel) + spawn_items(pos, items_to_spawn) end end end diff --git a/mod.conf b/mod.conf index 7a095b1..8966913 100644 --- a/mod.conf +++ b/mod.conf @@ -1 +1,2 @@ name = item_drop +description = A highly configurable mod providing item magnet and in-world node drops diff --git a/settingtypes.txt b/settingtypes.txt index 4896788..14df02c 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -8,7 +8,7 @@ item_drop.enable_item_drop (Enable item drops) bool true item_drop.enable_pickup_key (Use pickup key) bool true #Collect items when the key is not pressed instead of when it is pressed -item_drop.pickup_keyinvert (Invert pickup key) bool false +item_drop.pickup_keyinvert (Invert pickup key) bool true #What keytype to use as pickup key item_drop.pickup_keytype (Pickup keytype) enum Use Use,Sneak,LeftAndRight,RMB,SneakAndRMB