Refactor item magnet and fix multi-player bug
The bug was that the item misbehaved when multiple players were close to an item entitymaster
parent
928a1e7692
commit
8231f21808
|
@ -1,8 +1,24 @@
|
|||
Builtin item mod
|
||||
================
|
||||
By PilzAdam
|
||||
Tweaked by Kaadmy, for Pixture
|
||||
Repixture builtin item mod
|
||||
==========================
|
||||
|
||||
Items are now destroyed by lava and flow with water.
|
||||
Item entities for Repixture.
|
||||
|
||||
Source license: LGPLv2.1
|
||||
Adds the custom handling for item entities (dropped items) by overriding
|
||||
`__builtin:item`. Item entities work similar to Minetest's builtin item entities.
|
||||
|
||||
Features:
|
||||
|
||||
* Basic physics (affected by gravity, collides)
|
||||
* Supports the `item_entity_ttl` setting (auto-delete item after some time)
|
||||
* Item magnet (player collects item automatically when close)
|
||||
* Item is destroyed by lava, fire or nodes that deal damage with `damage_per_second`
|
||||
* Notifies rp_nav when the map item was collected
|
||||
* If the group `no_item_drop` is present in the item definition, or
|
||||
the item entity will be instantly deleted
|
||||
|
||||
## Licensing
|
||||
Credits: Originally by PilzAdam (released under the name `builtin_item`),
|
||||
then tweaked by Kaadmy for Pixture.
|
||||
|
||||
Source code license: LGPLv2.1
|
||||
Media license: CC BY-SA 4.0
|
||||
|
|
|
@ -6,6 +6,28 @@
|
|||
--
|
||||
local GRAVITY = tonumber(minetest.settings:get("movement_gravity")) or 9.81
|
||||
|
||||
local nav_mod = minetest.get_modpath("rp_nav") ~= nil
|
||||
|
||||
-- Distance from player to item
|
||||
-- below which the item magnet kicks in
|
||||
-- and starts attracting the item.
|
||||
local ITEM_MAGNET_ACTIVE_DISTANCE = 1.5
|
||||
|
||||
-- Distance from player to item
|
||||
-- below which the player's item magnet
|
||||
-- will collect the item into the inventory.
|
||||
local ITEM_MAGNET_COLLECT_DISTANCE = 0.5
|
||||
|
||||
-- Distance above ground at which players
|
||||
-- will collect items
|
||||
local ITEM_MAGNET_HAND_HEIGHT = 0.5
|
||||
|
||||
-- Movement speed at which the item
|
||||
-- magnet attracts items
|
||||
local ITEM_MAGNET_ATTRACT_SPEED = 5
|
||||
|
||||
|
||||
|
||||
local function add_item_death_particle(ent)
|
||||
minetest.add_particle({
|
||||
pos = ent.object:get_pos(),
|
||||
|
@ -33,7 +55,7 @@ minetest.register_entity(
|
|||
timer = 0,
|
||||
item_magnet_timer = 0,
|
||||
},
|
||||
|
||||
|
||||
itemstring = "",
|
||||
physical_state = true,
|
||||
item_magnet = false, -- set by other mod that implements item magnet
|
||||
|
@ -99,45 +121,135 @@ minetest.register_entity(
|
|||
self.object:set_acceleration({x=0, y=-GRAVITY, z=0})
|
||||
self:set_item(self.itemstring)
|
||||
end,
|
||||
|
||||
|
||||
on_step = function(self, dtime)
|
||||
local itempos = self.object:get_pos()
|
||||
|
||||
-- Remove item if old
|
||||
local time_to_live = tonumber(minetest.settings:get("item_entity_ttl"))
|
||||
if not time_to_live then time_to_live = 900 end
|
||||
if not self.timer then self.timer = 0 end
|
||||
if not self.item_magnet_timer then self.item_magnet_timer = 0 end
|
||||
|
||||
|
||||
self.timer = self.timer + dtime
|
||||
if self.item_magnet_timer >= 0 then
|
||||
self.item_magnet_timer = self.item_magnet_timer - dtime
|
||||
end
|
||||
if time_to_live ~= -1 and (self.timer > time_to_live) then
|
||||
add_item_death_particle(self)
|
||||
minetest.log("action", "[rp_builtin_item] Item entity removed due to timeout at "..minetest.pos_to_string(self.object:get_pos()))
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
local p = self.object:get_pos()
|
||||
|
||||
local name = minetest.get_node(p).name
|
||||
local def = minetest.registered_nodes[name]
|
||||
-- Destroy item in damaging node
|
||||
if def and def.damage_per_second > 0 then
|
||||
if minetest.get_item_group(name, "lava") ~= 0 or minetest.get_item_group(name, "fire") ~= 0 then
|
||||
minetest.sound_play("builtin_item_lava", {pos = self.object:get_pos(), gain = 0.45})
|
||||
end
|
||||
add_item_death_particle(self)
|
||||
minetest.log("action", "[rp_builtin_item] Item entity destroyed in damaging node at "..minetest.pos_to_string(self.object:get_pos()))
|
||||
minetest.log("action", "[rp_builtin_item] Item entity removed due to timeout at "..minetest.pos_to_string(itempos))
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
if self.item_magnet then
|
||||
local nodename = minetest.get_node(itempos).name
|
||||
local def = minetest.registered_nodes[nodename]
|
||||
-- Destroy item in damaging node
|
||||
if def and def.damage_per_second > 0 then
|
||||
if minetest.get_item_group(nodename, "lava") ~= 0 or minetest.get_item_group(nodename, "fire") ~= 0 then
|
||||
minetest.sound_play("builtin_item_lava", {pos = itempos, gain = 0.45})
|
||||
end
|
||||
add_item_death_particle(self)
|
||||
minetest.log("action", "[rp_builtin_item] Item entity destroyed in damaging node at "..minetest.pos_to_string(itempos))
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
|
||||
p.y = p.y - 0.3
|
||||
local nn = minetest.get_node(p).name
|
||||
|
||||
-- Item magnet: Attract item to closest living player
|
||||
|
||||
local object = self.object
|
||||
local objects_around = minetest.get_objects_inside_radius(self.object:get_pos(), ITEM_MAGNET_ACTIVE_DISTANCE)
|
||||
local closest_dist = math.huge
|
||||
local closest_player = nil
|
||||
local playerpos
|
||||
for o=1, #objects_around do
|
||||
local player = objects_around[o]
|
||||
if player:is_player() then
|
||||
playerpos = player:get_pos()
|
||||
playerpos.y = playerpos.y + ITEM_MAGNET_HAND_HEIGHT
|
||||
if vector.distance(playerpos, itempos) < closest_dist and player:get_hp() > 0 then
|
||||
closest_dist = vector.distance(playerpos, itempos)
|
||||
closest_player = player
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local lua = object:get_luaentity()
|
||||
|
||||
if object == nil or lua == nil or lua.itemstring == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- Item magnet handling
|
||||
local len, vec
|
||||
if closest_player then
|
||||
--playerpos.y = playerpos.y + ITEM_MAGNET_HAND_HEIGHT
|
||||
vec = {
|
||||
x = playerpos.x - itempos.x,
|
||||
y = playerpos.y - itempos.y,
|
||||
z = playerpos.z - itempos.z
|
||||
}
|
||||
len = vector.length(vec)
|
||||
end
|
||||
if closest_player ~= nil and lua.item_magnet_timer <= 0 and len < ITEM_MAGNET_ACTIVE_DISTANCE then
|
||||
local inv = closest_player:get_inventory()
|
||||
-- Activate item magnet
|
||||
if inv and inv:room_for_item("main", ItemStack(lua.itemstring)) then
|
||||
if len >= ITEM_MAGNET_COLLECT_DISTANCE then
|
||||
-- Attract item to player
|
||||
vec = vector.divide(vec, len) -- It's a normalize but we have len yet (vector.normalize(vec))
|
||||
|
||||
vec.x = vec.x*ITEM_MAGNET_ATTRACT_SPEED
|
||||
vec.y = vec.y*ITEM_MAGNET_ATTRACT_SPEED
|
||||
vec.z = vec.z*ITEM_MAGNET_ATTRACT_SPEED
|
||||
|
||||
object:set_velocity(vec)
|
||||
object:set_properties({ physical = false })
|
||||
self.item_magnet = true
|
||||
return
|
||||
else
|
||||
-- Player collects item if close enough
|
||||
if inv:room_for_item("main", ItemStack(lua.itemstring)) then
|
||||
if minetest.is_creative_enabled(closest_player:get_player_name()) then
|
||||
if not inv:contains_item("main", ItemStack(lua.itemstring), true) then
|
||||
inv:add_item("main", ItemStack(lua.itemstring))
|
||||
end
|
||||
else
|
||||
inv:add_item("main", ItemStack(lua.itemstring))
|
||||
end
|
||||
|
||||
if lua.itemstring ~= "" then
|
||||
minetest.sound_play(
|
||||
"builtin_item_pickup",
|
||||
{
|
||||
pos = itempos,
|
||||
gain = 0.3,
|
||||
max_hear_distance = 16
|
||||
}, true)
|
||||
end
|
||||
|
||||
-- Notify nav mod of inventory change
|
||||
if nav_mod and lua.itemstring == "rp_nav:map" then
|
||||
nav.map.update_hud_flags(closest_player)
|
||||
end
|
||||
|
||||
lua.itemstring = ""
|
||||
object:remove()
|
||||
return
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Deactivate item magnet if out of range
|
||||
if lua.item_magnet then
|
||||
object:set_velocity({x = 0, y = object:get_velocity().y, z = 0})
|
||||
lua.item_magnet = false
|
||||
end
|
||||
end
|
||||
|
||||
itempos.y = itempos.y - 0.3
|
||||
local nn = minetest.get_node(itempos).name
|
||||
-- If node is not registered or node is walkably solid:
|
||||
if not minetest.registered_nodes[nn] or minetest.registered_nodes[nn].walkable then
|
||||
if self.physical_state then
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
Item drop mod
|
||||
=============
|
||||
By PilzAdam
|
||||
Tweaked by Kaadmy, for Pixture
|
||||
|
||||
Asset license: CC BY-SA 4.0
|
||||
Adds custom item drop handling.
|
||||
|
||||
If a node is dug, its drop will appear as items on the ground.
|
||||
|
||||
## License
|
||||
Credits: Originally by PilzAdam, then
|
||||
tweaked by Kaadmy for Pixture
|
||||
|
||||
Source license: LGPLv2.1
|
||||
|
|
|
@ -1,36 +1,10 @@
|
|||
|
||||
--
|
||||
-- Item drop mod
|
||||
-- By PilzAdam
|
||||
-- Tweaked by Kaadmy, for Pixture
|
||||
--
|
||||
|
||||
local nav_mod = minetest.get_modpath("rp_nav") ~= nil
|
||||
|
||||
item_drop = {}
|
||||
|
||||
-- Distance from player to item
|
||||
-- below which the item magnet kicks in
|
||||
-- and starts attracting the item.
|
||||
local ITEM_MAGNET_ACTIVE_DISTANCE = 1.5
|
||||
|
||||
-- Distance from player to item
|
||||
-- below which the player's item magnet
|
||||
-- will collect the item into the inventory.
|
||||
local ITEM_MAGNET_COLLECT_DISTANCE = 0.5
|
||||
|
||||
-- Distance above ground at which players
|
||||
-- will collect items
|
||||
local ITEM_MAGNET_HAND_HEIGHT = 0.5
|
||||
|
||||
-- Movement speed at which the item
|
||||
-- magnet attracts items
|
||||
local ITEM_MAGNET_ATTRACT_SPEED = 5
|
||||
|
||||
-- Time in seconds for which the item magnet is
|
||||
-- inactive after being dropped by a player
|
||||
local ITEM_MAGNET_DELAY_AFTER_DROP = 1.5
|
||||
|
||||
item_drop = {}
|
||||
function item_drop.drop_item(pos, itemstack)
|
||||
local rpos = {
|
||||
x = pos.x + math.random(-0.3, 0.3),
|
||||
|
@ -88,102 +62,6 @@ minetest.item_drop = function(itemstack, dropper, pos)
|
|||
end
|
||||
end
|
||||
|
||||
local function valid(object)
|
||||
local ent = object:get_luaentity()
|
||||
return ent.timer ~= nil and ent.item_magnet_timer ~= nil
|
||||
end
|
||||
|
||||
minetest.register_globalstep(
|
||||
function(dtime)
|
||||
for _,player in ipairs(minetest.get_connected_players()) do
|
||||
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
|
||||
local pos = player:get_pos()
|
||||
local inv = player:get_inventory()
|
||||
|
||||
local in_radius = minetest.get_objects_inside_radius(pos, 6.0)
|
||||
|
||||
for _,object in ipairs(in_radius) do
|
||||
if not object:is_player() and object:get_luaentity()
|
||||
and object:get_luaentity().name == "__builtin:item" and valid(object) then
|
||||
local pos1 = table.copy(pos)
|
||||
|
||||
pos1.y = pos1.y + ITEM_MAGNET_HAND_HEIGHT
|
||||
|
||||
local pos2 = object:get_pos()
|
||||
|
||||
local vec = {
|
||||
x = pos1.x - pos2.x,
|
||||
y = pos1.y - pos2.y,
|
||||
z = pos1.z - pos2.z
|
||||
}
|
||||
|
||||
local len = vector.length(vec)
|
||||
|
||||
local lua = object:get_luaentity()
|
||||
|
||||
if object == nil or lua == nil or lua.itemstring == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- Item magnet handling
|
||||
if len < ITEM_MAGNET_ACTIVE_DISTANCE and lua.item_magnet_timer <= 0 then
|
||||
-- Activate item magnet
|
||||
if inv and inv:room_for_item("main", ItemStack(lua.itemstring)) then
|
||||
if len >= ITEM_MAGNET_COLLECT_DISTANCE then
|
||||
-- Attract item to player
|
||||
vec = vector.divide(vec, len) -- It's a normalize but we have len yet (vector.normalize(vec))
|
||||
|
||||
vec.x = vec.x*ITEM_MAGNET_ATTRACT_SPEED
|
||||
vec.y = vec.y*ITEM_MAGNET_ATTRACT_SPEED
|
||||
vec.z = vec.z*ITEM_MAGNET_ATTRACT_SPEED
|
||||
|
||||
lua.item_magnet = true
|
||||
object:set_velocity(vec)
|
||||
object:set_properties({ physical = false })
|
||||
|
||||
else
|
||||
-- Player collects item if close enough
|
||||
if inv:room_for_item("main", ItemStack(lua.itemstring)) then
|
||||
if minetest.is_creative_enabled(player:get_player_name()) then
|
||||
if not inv:contains_item("main", ItemStack(lua.itemstring), true) then
|
||||
inv:add_item("main", ItemStack(lua.itemstring))
|
||||
end
|
||||
else
|
||||
inv:add_item("main", ItemStack(lua.itemstring))
|
||||
end
|
||||
|
||||
if lua.itemstring ~= "" then
|
||||
minetest.sound_play(
|
||||
"item_drop_pickup",
|
||||
{
|
||||
pos = pos,
|
||||
gain = 0.3,
|
||||
max_hear_distance = 16
|
||||
}, true)
|
||||
end
|
||||
-- Notify nav mod of inventory change
|
||||
if nav_mod and lua.itemstring == "rp_nav:map" then
|
||||
nav.map.update_hud_flags(player)
|
||||
end
|
||||
|
||||
lua.itemstring = ""
|
||||
object:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Deactivate item magnet if out of range
|
||||
if lua.item_magnet then
|
||||
object:set_velocity({x = 0, y = object:get_velocity().y, z = 0})
|
||||
lua.item_magnet = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function minetest.handle_node_drops(pos, drops, digger)
|
||||
-- If digger is in Creative Mode, give items directly to digger
|
||||
if digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name()) then
|
||||
|
|
Loading…
Reference in New Issue