summaryrefslogtreecommitdiff
path: root/item_tweaks
diff options
context:
space:
mode:
Diffstat (limited to 'item_tweaks')
-rw-r--r--item_tweaks/init.lua3
-rw-r--r--item_tweaks/item_drop.lua314
-rw-r--r--item_tweaks/sounds/item_drop.oggbin0 -> 7367 bytes
-rw-r--r--item_tweaks/sounds/item_drop_pickup.1.oggbin0 -> 9981 bytes
-rw-r--r--item_tweaks/sounds/item_drop_pickup.2.oggbin0 -> 10477 bytes
-rw-r--r--item_tweaks/sounds/item_drop_pickup.3.oggbin0 -> 9586 bytes
-rw-r--r--item_tweaks/sounds/item_drop_pickup.4.oggbin0 -> 9696 bytes
7 files changed, 317 insertions, 0 deletions
diff --git a/item_tweaks/init.lua b/item_tweaks/init.lua
new file mode 100644
index 0000000..efad17f
--- /dev/null
+++ b/item_tweaks/init.lua
@@ -0,0 +1,3 @@
+local modpath = minetest.get_modpath(minetest.get_current_modname())
+
+dofile(modpath.."/item_drop.lua")
diff --git a/item_tweaks/item_drop.lua b/item_tweaks/item_drop.lua
new file mode 100644
index 0000000..beed1c7
--- /dev/null
+++ b/item_tweaks/item_drop.lua
@@ -0,0 +1,314 @@
+-- item_drop code by cyisfor
+-- https://github.com/cyisfor/item_drop
+
+
+if drops == nil then
+ drops = {}
+end
+
+local movers = {}
+
+local removedAlreadyDammit = {}
+
+vector.fixedNormalize = function(v)
+ assert(v)
+ local len = vector.length(v)
+ if len == 0 then
+ -- no length 1 vector will ever equal this
+ return vector.new(0,0,0)
+ else
+ return vector.divide(v, len)
+ end
+end
+
+if not vector.dot then
+ vector.dot = function(p1,p2)
+ return p1.x * p2.x + p1.y * p2.y + p1.z * p2.z
+ end
+end
+
+local function removeObject(object)
+ movers[object] = nil
+ removedAlreadyDammit[object] = true
+ object:remove()
+end
+
+local function removeObjectWithSound(object)
+ movers[object] = nil
+ removedAlreadyDammit[object] = true
+ local pos=object:getpos()
+ minetest.sound_play("item_gone", {
+ pos=pos,
+ gain = 0.2,
+ max_hear_distance = 32,
+ })
+ object:remove()
+end
+
+-- returns whether the pickup failed or not.
+-- nil pickupRadius means to infinity and beyond
+local function pickup(player, inv, object, pickupRadius)
+ if removedAlreadyDammit[object] then
+ -- this gets called after the timeout, as well as when it hits the player
+ return true
+ end
+ if player == nil then return true end
+
+ -- itemstring is serialized item so includes metadata
+ local lua = object:get_luaentity()
+ item = ItemStack(lua.itemstring)
+ if inv and inv:room_for_item("main", item) then
+ inv:add_item("main", item)
+ if object:get_luaentity().itemstring ~= "" then
+ minetest.sound_play("item_drop_pickup", {
+ to_player = player:get_player_name(),
+ gain = 0.4,
+ })
+ end
+ lua.itemstring = ''
+ removeObject(object)
+ return false
+ else
+ return true
+ end
+end
+
+local function isGood(object)
+ -- only want items swooping up after players, not after chests!
+ if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then
+ return true
+ else
+ return false
+ end
+end
+
+local function stop(object)
+ movers[object] = nil
+ -- no pickup, even though it's close, so
+ -- stop moving towards the player
+ object:setvelocity({x=0, y=0, z=0})
+ object:setacceleration({x=0, y=0, z=0})
+ -- also we can walk on it and it can push pressure plates
+ -- physical_state = false means "please make us physical again"
+ local lua = object:get_luaentity()
+ if lua then
+ lua.physical_state = false
+ end
+ --object:set_properties({
+ -- physical = true
+ --})
+end
+
+local function pickupOrStop(object, inv, player, pickupRadius)
+ local lua = object:get_luaentity()
+ if object == nil or lua == nil or lua.itemstring == nil then
+ return
+ end
+ if pickup(player, inv, object, pickupRadius) then
+ stop(object)
+ end
+end
+
+-- GMass... it's the player's mass if the player were a giant planetlike object
+-- which things orbit around
+-- in the following units:
+-- if G = 6.67×10−11 then
+-- GMass = 1 for 14,992,503,748 kilograms
+drops.playerGMass = 1.7
+-- the player is faaaaaaaat
+
+local function moveTowards(object, player, pickupRadius, attractRadius)
+ -- move it towards the player, then pick it up after a delay!
+ local pos1 = player:getpos()
+ if pos1 == nil then return end
+ local pos2 = object:getpos()
+ if pos2 == nil then return end
+ pos1.y = pos1.y+0.5 -- head towards player's belt
+ local direct = vector.subtract(pos1, pos2)
+ local R = vector.length(direct)
+ v = object:getvelocity()
+ stopped = v.x == 0 and v.y == 0 and v.z == 0
+ -- when direction(X) = direction(V) we passed the player
+ -- so project V onto X. If same, passed. If not, approaching.
+ -- projection = norm(X) * (length(V) * cos(theta))
+ -- => length(V) * dot(V,X) / length(V) / length(X)
+ -- = dot(V,X) / length(X)
+ -- if X is normalized, length(X) == 1 so... dot product!
+ -- sign(dot) > 0 = same direction sign(dot)< 0 = different
+ direct = vector.fixedNormalize(direct)
+
+ -- idea, set velocity not acceleration but set it
+ -- not to velocity + acceleration, but to the projection of that
+ -- onto the direction vector. object will always have velocity towards YOU
+
+ if R > attractRadius then
+ stop(object)
+ return
+ end
+ if R < pickupRadius or (not stopped and vector.dot(v,direct) < 0) then
+ pickupOrStop(object,player:get_inventory(),player,nil)
+ return
+ end
+ -- Fg = G*M1*M2/R^2
+ -- M1*A1 = G * M1 * M2 / R^2
+ -- A1 = G * M2 / R ^2
+ -- G = whatever it takes for stuff to orbit around the player
+ -- and the weight of the player is ^^^
+ -- A1 = C / R^2
+ local A
+ A = drops.playerGMass / R^2
+ A = math.max(A,2*drops.playerGMass)
+ object:setacceleration(vector.multiply(direct,A))
+end
+
+if minetest.setting_get("enable_item_pickup") == "true" then
+ local tickets = 0 -- XXX: oy vey
+ moveDelay = 0
+ minetest.register_globalstep(function(dtime)
+ -- it's much more efficient to just restart... no way to unregister_globalstep right?
+ if not minetest.setting_get("enable_item_pickup") then return end
+ moveDelay = moveDelay + dtime
+ local pickupRadius = tonumber(minetest.setting_get("pickup_radius"))
+ local attractRadius = tonumber(minetest.setting_get("attract_radius"))
+ if not pickupRadius then pickupRadius = 0.5 end
+ if not attractRadius then attractRadius = 3 end
+
+ if moveDelay > 0.1 then
+ moveDelay = 0
+ -- correct your trajectory while moving
+ for object,pair in pairs(movers) do
+ local player = pair[1]
+ moveTowards(object,player,pickupRadius,attractRadius)
+ end
+ end
+ for _, player in ipairs(minetest.get_connected_players()) do
+ if player:get_hp() > 0 or not minetest.setting_getbool("enable_damage") then
+ local playerPosition = player:getpos()
+ if playerPosition ~= nil then
+ playerPosition.y = playerPosition.y + 0.5
+ local inv = player:get_inventory()
+
+ for _, object in ipairs(minetest.get_objects_inside_radius(playerPosition, 3)) do
+ if isGood(object) and (object:get_luaentity().dropped_by ~= player:get_player_name() or object:get_luaentity().age > 3) and
+ inv and
+ inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring))
+ then
+ local ticket = tickets
+ movers[object] = {player,ticket}
+ tickets = tickets + 1
+ moveTowards(object, player, pickupRadius, attractRadius)
+ -- make sure object doesn't push the player around!
+ object:get_luaentity().physical_state = true
+ object:get_luaentity().object:set_properties({
+ physical = false,
+ collide_with_objects = false,
+ weight = 0
+ })
+ -- pleeease no immortal orbiting entities
+ -- unless you want them to be >:)
+ minetest.after(30, function(object)
+ -- only if it's still moving
+ -- but what if it started moving a second time?
+ pair = movers[object]
+ if pair and pair[2] == ticket then
+ stop(object)
+ end
+ end, object)
+ end
+ end
+ end
+ end
+ end
+ end)
+end
+
+if minetest.setting_get("enable_item_drops") == "true" then
+ local old_handle_node_drops = minetest.handle_node_drops
+
+ function new_handle_node_drops(pos, drops, digger)
+ if digger and digger.is_fake_player then
+ return old_handle_node_drops(pos, drops, digger)
+ end
+ local inv
+ -- the digger might be a node, like a constructor
+ if minetest.setting_getbool("creative_mode") and digger and digger:is_player() then
+ inv = digger:get_inventory()
+ end
+ for _, item in ipairs(drops) do
+ local count, name
+ if type(item) == "string" then
+ count = 1
+ name = item
+ else
+ count = item:get_count()
+ name = item:get_name()
+ end
+ -- Only drop the item if not in creative, or if the item is not in creative inventory
+ if not inv or not inv:contains_item("main", ItemStack(name)) then
+ for i=1, count do
+ local obj = minetest.add_item(pos, item)
+ if obj ~= nil then
+ local x = math.random(1, 5)
+ if math.random(1, 2) == 1 then
+ x = -x
+ end
+ local z = math.random(1, 5)
+ if math.random(1, 2) == 1 then
+ z = -z
+ end
+ -- hurl it out into space at a random velocity
+ -- (still falling though)
+ obj:setvelocity({x=1/x, y=obj:getvelocity().y, z=1/z})
+ end
+ end
+ end
+ end
+ -- the items have been dropped. Don't use builtin/item.lua or it could put the items
+ -- into an inventory! (see quarry)
+ -- return old_handle_node_drops(pos, drops, digger)
+ end
+
+ function checkSetting(pos, drops, digger)
+ if minetest.setting_get("enable_item_drops") == "true" then
+ return new_handle_node_drops(pos, drops, digger)
+ else
+ return old_handle_node_drops(pos, drops, digger)
+ end
+ end
+ minetest.handle_node_drops = checkSetting
+
+end
+
+function minetest.item_drop(itemstack, dropper, pos)
+ if dropper and dropper.get_player_name then
+ local v = dropper:get_look_dir()
+ local p = {x=pos.x+v.x, y=pos.y+1.5+v.y, z=pos.z+v.z}
+ local r
+ if dropper:get_player_control().sneak then
+ r = itemstack
+ itemstack = itemstack:to_table()
+ itemstack.count = 1
+ itemstack = ItemStack(itemstack)
+ r:take_item()
+ else
+ r = ItemStack("")
+ end
+ minetest.sound_play("item_drop", {
+ pos=pos,
+ gain = 1.0,
+ max_hear_distance = 32,
+ })
+ local obj = minetest.add_item(p, itemstack)
+ if obj then
+ v.x = v.x*2
+ v.y = v.y*2 + 1
+ v.z = v.z*2
+ obj:setvelocity(v)
+ obj:get_luaentity().dropped_by = dropper:get_player_name()
+ end
+ return r
+ else
+ minetest.add_item(pos, itemstack)
+ return ItemStack("")
+ end
+end
diff --git a/item_tweaks/sounds/item_drop.ogg b/item_tweaks/sounds/item_drop.ogg
new file mode 100644
index 0000000..ced91f8
--- /dev/null
+++ b/item_tweaks/sounds/item_drop.ogg
Binary files differ
diff --git a/item_tweaks/sounds/item_drop_pickup.1.ogg b/item_tweaks/sounds/item_drop_pickup.1.ogg
new file mode 100644
index 0000000..2ae432d
--- /dev/null
+++ b/item_tweaks/sounds/item_drop_pickup.1.ogg
Binary files differ
diff --git a/item_tweaks/sounds/item_drop_pickup.2.ogg b/item_tweaks/sounds/item_drop_pickup.2.ogg
new file mode 100644
index 0000000..f58bf08
--- /dev/null
+++ b/item_tweaks/sounds/item_drop_pickup.2.ogg
Binary files differ
diff --git a/item_tweaks/sounds/item_drop_pickup.3.ogg b/item_tweaks/sounds/item_drop_pickup.3.ogg
new file mode 100644
index 0000000..cf57c94
--- /dev/null
+++ b/item_tweaks/sounds/item_drop_pickup.3.ogg
Binary files differ
diff --git a/item_tweaks/sounds/item_drop_pickup.4.ogg b/item_tweaks/sounds/item_drop_pickup.4.ogg
new file mode 100644
index 0000000..bfe99d9
--- /dev/null
+++ b/item_tweaks/sounds/item_drop_pickup.4.ogg
Binary files differ