2 function minetest.handle_node_drops(pos, drops, digger)
3 for _,item in ipairs(drops) do
5 if type(item) == "string" then
9 count = item:get_count()
10 name = item:get_name()
13 local obj = minetest.add_item(pos, name)
15 local x=math.random(-2,2)*math.random()
16 local y=math.random(2,5)
17 local z=math.random(-2,2)*math.random()
18 obj:setvelocity({x=x, y=y, z=z})
19 obj:get_luaentity().collection_timer = 2.3
26 -- Minetest: builtin/item_entity.lua
28 function minetest.spawn_item(pos, item)
29 -- Take item in any format
30 local stack = ItemStack(item)
31 local obj = minetest.add_entity(pos, "__builtin:item")
32 -- Don't use obj if it couldn't be added to the map.
34 obj:get_luaentity():set_item(stack:to_string())
39 function minetest.throw_item(pos, item)
40 -- Take item in any format
41 local stack = ItemStack(item)
42 local obj = minetest.add_entity(pos, "__builtin:item")
43 -- Don't use obj if it couldn't be added to the map.
45 obj:get_luaentity():set_item(stack:to_string())
46 local x=math.random(-2,2)*math.random()
47 local y=math.random(2,5)
48 local z=math.random(-2,2)*math.random()
49 obj:setvelocity({x=x, y=y, z=z})
50 obj:get_luaentity().collection_timer = 2.3
55 -- If item_entity_ttl is not set, enity will have default life time
56 -- Setting it to -1 disables the feature
58 local time_to_live = tonumber(minetest.settings:get("item_entity_ttl")) or 900
59 local gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.81
62 minetest.register_entity(":__builtin:item", {
63 initial_properties = {
66 collide_with_objects = false,
67 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
69 visual_size = {x = 0.4, y = 0.4},
71 spritediv = {x = 1, y = 1},
72 initial_sprite_basepos = {x = 0, y = 0},
79 slippery_state = false,
80 physical_state = true,
83 -- Pushing item out of solid nodes
85 force_out_start = nil,
86 --Collection Variables
93 set_item = function(self, item)
94 local stack = ItemStack(item or self.itemstring)
95 self.itemstring = stack:to_string()
96 if self.itemstring == "" then
101 -- Backwards compatibility: old clients use the texture
102 -- to get the type of the item
103 local itemname = stack:is_known() and stack:get_name() or "unknown"
105 local max_count = stack:get_stack_max()
106 local count = math.min(stack:get_count(), max_count)
107 local size = 0.2 + 0.1 * (count / max_count) ^ (1 / 3)
108 local coll_height = size * 0.75
109 local def = minetest.registered_nodes[itemname]
110 local glow = def and def.light_source
112 self.object:set_properties({
114 visual = "wielditem",
115 textures = {itemname},
116 visual_size = {x = size, y = size},
117 collisionbox = {-size, -coll_height, -size,
118 size, coll_height, size},
119 selectionbox = {-size, -size, -size, size, size, size},
120 automatic_rotate = math.pi * 0.5 * 0.2 / size,
121 wield_item = self.itemstring,
127 get_staticdata = function(self)
128 return minetest.serialize({
129 itemstring = self.itemstring,
131 dropped_by = self.dropped_by,
133 collection_timer = self.collection_timer,
134 collectable = self.collectable,
135 try_timer = self.try_timer,
136 collected = self.collected,
137 delete_timer = self.delete_timer,
142 on_activate = function(self, staticdata, dtime_s)
143 if string.sub(staticdata, 1, string.len("return")) == "return" then
144 local data = minetest.deserialize(staticdata)
145 if data and type(data) == "table" then
146 self.itemstring = data.itemstring
147 self.age = (data.age or 0) + dtime_s
148 self.dropped_by = data.dropped_by
150 self.collection_timer = data.collection_timer
151 self.collectable = data.collectable
152 self.try_timer = data.try_timer
153 self.collected = data.collected
154 self.delete_timer = data.delete_timer
157 self.itemstring = staticdata
159 self.object:set_armor_groups({immortal = 1})
160 self.object:set_velocity({x = 0, y = 2, z = 0})
161 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
165 enable_physics = function(self)
166 if not self.physical_state then
167 self.physical_state = true
168 self.object:set_properties({physical = true})
169 self.object:set_velocity({x=0, y=0, z=0})
170 self.object:set_acceleration({x=0, y=-gravity, z=0})
174 disable_physics = function(self)
175 if self.physical_state then
176 self.physical_state = false
177 self.object:set_properties({physical = false})
178 self.object:set_velocity({x=0, y=0, z=0})
179 self.object:set_acceleration({x=0, y=0, z=0})
182 on_step = function(self, dtime)
184 if self.collected == true then
185 self.object:setvelocity(vector.new(0,0,0))
186 self.object:setacceleration(vector.new(0,0,0))
188 self.delete_timer = self.delete_timer + dtime
189 --this is where the item gets removed from world
190 if self.delete_timer > 0.2 then
196 --allow entity to be collected after timer
197 if self.collectable == false and self.collection_timer >= 2.5 then
198 self.collectable = true
199 elseif self.collectable == false then
200 self.collection_timer = self.collection_timer + dtime
203 self.age = self.age + dtime
204 if time_to_live > 0 and self.age > time_to_live then
210 local pos = self.object:get_pos()
211 local node = minetest.get_node_or_nil({
213 y = pos.y + self.object:get_properties().collisionbox[2] - 0.05,
216 -- Delete in 'ignore' nodes
217 if node and node.name == "ignore" then
223 local is_stuck = false
224 local snode = minetest.get_node_or_nil(pos)
226 local sdef = minetest.registered_nodes[snode.name] or {}
227 is_stuck = (sdef.walkable == nil or sdef.walkable == true)
228 and (sdef.collision_box == nil or sdef.collision_box.type == "regular")
229 and (sdef.node_box == nil or sdef.node_box.type == "regular")
232 -- Push item out when stuck inside solid node
236 {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
237 {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
240 -- Check which one of the 4 sides is free
242 local cnode = minetest.get_node(vector.add(pos, order[o])).name
243 local cdef = minetest.registered_nodes[cnode] or {}
244 if cnode ~= "ignore" and cdef.walkable == false then
249 -- If none of the 4 sides is free, check upwards
251 shootdir = {x=0, y=1, z=0}
252 local cnode = minetest.get_node(vector.add(pos, shootdir)).name
253 if cnode == "ignore" then
254 shootdir = nil -- Do not push into ignore
259 -- Set new item moving speed accordingly
260 local newv = vector.multiply(shootdir, 3)
261 self:disable_physics()
262 self.object:set_velocity(newv)
264 self.force_out = newv
265 self.force_out_start = vector.round(pos)
268 elseif self.force_out then
269 -- This code runs after the entity got a push from the above code.
270 -- It makes sure the entity is entirely outside the solid node
271 local c = self.object:get_properties().collisionbox
272 local s = self.force_out_start
273 local f = self.force_out
274 local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
275 (f.y > 0 and pos.y + c[2] > s.y + 0.5) or
276 (f.z > 0 and pos.z + c[3] > s.z + 0.5) or
277 (f.x < 0 and pos.x + c[4] < s.x - 0.5) or
278 (f.z < 0 and pos.z + c[6] < s.z - 0.5)
280 -- Item was successfully forced out
282 self:enable_physics()
286 if not self.physical_state then
287 return -- Don't do anything
290 -- Slide on slippery nodes
291 local vel = self.object:get_velocity()
292 local def = node and minetest.registered_nodes[node.name]
293 local is_moving = (def and not def.walkable) or
294 vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
295 local is_slippery = false
297 if def and def.walkable then
298 local slippery = minetest.get_item_group(node.name, "slippery")
299 is_slippery = slippery ~= 0
300 if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
301 -- Horizontal deceleration
302 local slip_factor = 4.0 / (slippery + 4)
303 self.object:set_acceleration({
304 x = -vel.x * slip_factor,
306 z = -vel.z * slip_factor
308 elseif vel.y == 0 then
313 if self.moving_state == is_moving and
314 self.slippery_state == is_slippery then
315 -- Do not update anything until the moving state changes
319 self.moving_state = is_moving
320 self.slippery_state = is_slippery
323 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
325 self.object:set_acceleration({x = 0, y = 0, z = 0})
326 self.object:set_velocity({x = 0, y = 0, z = 0})
332 --The item collection magnet
334 local eye_height = 1.1
335 minetest.register_globalstep(function(dtime)
337 for _,player in ipairs(minetest.get_connected_players()) do
338 --don't magnetize to dead players
339 if player:get_hp() > 0 then
340 local pos = player:getpos()
341 local inv = player:get_inventory()
343 for _,object in ipairs(minetest.get_objects_inside_radius({x=pos.x,y=pos.y+eye_height,z=pos.z}, 3)) do
344 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" then
345 if inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
346 if object:get_luaentity().collectable == true and object:get_luaentity().collected == false then
347 minetest.sound_play("pickup", {
350 pitch = math.random(60,100)/100
352 inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
353 object:moveto({x=pos.x,y=pos.y+eye_height,z=pos.z})
354 object:get_luaentity().collected = true