2 collection.collection_height = 0.5 -- the height of the collection based off the player's origin y height
3 collection.magnet_radius = 2 -- the radius of the item magnet
4 collection.allow_lower = false -- false = items below origin y of player will not be collected --true = player will collect all objects in radius --false = minecraft style --true = pilzadam style
5 collection.collection_time = 2.5 --the time which the item will be collected
7 local path = minetest.get_modpath("itemhandling")
8 dofile(path.."/magnet.lua")
11 function minetest.handle_node_drops(pos, drops, digger)
12 for _,item in ipairs(drops) do
14 if type(item) == "string" then
18 count = item:get_count()
19 name = item:get_name()
22 local obj = minetest.add_item(pos, name)
24 local x=math.random(-2,2)*math.random()
25 local y=math.random(2,5)
26 local z=math.random(-2,2)*math.random()
27 obj:setvelocity({x=x, y=y, z=z})
28 obj:get_luaentity().collection_timer = 2.3
35 -- Minetest: builtin/item_entity.lua
37 function minetest.spawn_item(pos, item)
38 -- Take item in any format
39 local stack = ItemStack(item)
40 local obj = minetest.add_entity(pos, "__builtin:item")
41 -- Don't use obj if it couldn't be added to the map.
43 obj:get_luaentity():set_item(stack:to_string())
48 function minetest.throw_item(pos, item)
49 -- Take item in any format
50 local stack = ItemStack(item)
51 local obj = minetest.add_entity(pos, "__builtin:item")
52 -- Don't use obj if it couldn't be added to the map.
54 obj:get_luaentity():set_item(stack:to_string())
55 local x=math.random(-2,2)*math.random()
56 local y=math.random(2,5)
57 local z=math.random(-2,2)*math.random()
58 obj:setvelocity({x=x, y=y, z=z})
59 obj:get_luaentity().collection_timer = 2.3
64 -- If item_entity_ttl is not set, enity will have default life time
65 -- Setting it to -1 disables the feature
67 local time_to_live = tonumber(minetest.settings:get("item_entity_ttl")) or 900
68 local gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.81
71 minetest.register_entity(":__builtin:item", {
72 initial_properties = {
75 collide_with_objects = false,
76 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
78 visual_size = {x = 0.4, y = 0.4},
80 spritediv = {x = 1, y = 1},
81 initial_sprite_basepos = {x = 0, y = 0},
88 slippery_state = false,
89 physical_state = true,
92 -- Pushing item out of solid nodes
94 force_out_start = nil,
95 --Collection Variables
97 collection_timer_goal = collection.collection_time,
98 collection_height = collection.collection_height,
103 radius = collection.magnet_radius,
105 set_item = function(self, item)
106 local stack = ItemStack(item or self.itemstring)
107 self.itemstring = stack:to_string()
108 if self.itemstring == "" then
109 -- item not yet known
113 -- Backwards compatibility: old clients use the texture
114 -- to get the type of the item
115 local itemname = stack:is_known() and stack:get_name() or "unknown"
117 local max_count = stack:get_stack_max()
118 local count = math.min(stack:get_count(), max_count)
119 local size = 0.2 + 0.1 * (count / max_count) ^ (1 / 3)
120 local coll_height = size * 0.75
121 local def = minetest.registered_nodes[itemname]
122 local glow = def and def.light_source
124 self.object:set_properties({
126 visual = "wielditem",
127 textures = {itemname},
128 visual_size = {x = size, y = size},
129 collisionbox = {-size, -coll_height, -size,
130 size, coll_height, size},
131 selectionbox = {-size, -size, -size, size, size, size},
132 automatic_rotate = math.pi * 0.5 * 0.2 / size,
133 wield_item = self.itemstring,
139 get_staticdata = function(self)
140 return minetest.serialize({
141 itemstring = self.itemstring,
143 dropped_by = self.dropped_by,
145 collection_timer = self.collection_timer,
146 collectable = self.collectable,
147 try_timer = self.try_timer,
148 collected = self.collected,
149 delete_timer = self.delete_timer,
154 on_activate = function(self, staticdata, dtime_s)
155 if string.sub(staticdata, 1, string.len("return")) == "return" then
156 local data = minetest.deserialize(staticdata)
157 if data and type(data) == "table" then
158 self.itemstring = data.itemstring
159 self.age = (data.age or 0) + dtime_s
160 self.dropped_by = data.dropped_by
162 self.collection_timer = data.collection_timer
163 self.collectable = data.collectable
164 self.try_timer = data.try_timer
165 self.collected = data.collected
166 self.delete_timer = data.delete_timer
169 self.itemstring = staticdata
171 self.object:set_armor_groups({immortal = 1})
172 self.object:set_velocity({x = 0, y = 2, z = 0})
173 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
177 enable_physics = function(self)
178 if not self.physical_state then
179 self.physical_state = true
180 self.object:set_properties({physical = true})
181 self.object:set_velocity({x=0, y=0, z=0})
182 self.object:set_acceleration({x=0, y=-gravity, z=0})
186 disable_physics = function(self)
187 if self.physical_state then
188 self.physical_state = false
189 self.object:set_properties({physical = false})
190 self.object:set_velocity({x=0, y=0, z=0})
191 self.object:set_acceleration({x=0, y=0, z=0})
194 on_step = function(self, dtime)
196 --if item set to be collected then only execute go to player
197 if self.collected == true then
198 if not self.collector then
199 self.collected = false
200 print("throwing exception")
203 local collector = minetest.get_player_by_name(self.collector)
205 self.object:setacceleration(vector.new(0,0,0))
206 self.disable_physics(self)
208 local pos = self.object:getpos()
209 local pos2 = collector:getpos()
210 pos2.y = pos2.y + self.collection_height
215 local direction = vector.normalize(vector.subtract(pos2,pos))
216 local distance = vector.distance(pos2,pos)
217 local multiplier = (self.radius*5) - distance
218 local velocity = vector.multiply(direction,multiplier)
219 self.object:setvelocity(velocity)
221 if distance < 0.2 then
226 --self.delete_timer = self.delete_timer + dtime
227 --this is where the item gets removed from world
228 --if self.delete_timer > 1 then
229 -- self.object:remove()
233 print(self.collector.." does not exist")
238 --allow entity to be collected after timer
239 if self.collectable == false and self.collection_timer >= self.collection_timer_goal then
240 self.collectable = true
241 elseif self.collectable == false then
242 self.collection_timer = self.collection_timer + dtime
245 self.age = self.age + dtime
246 if time_to_live > 0 and self.age > time_to_live then
252 local pos = self.object:get_pos()
253 local node = minetest.get_node_or_nil({
255 y = pos.y + self.object:get_properties().collisionbox[2] - 0.05,
258 -- Delete in 'ignore' nodes
259 if node and node.name == "ignore" then
265 local is_stuck = false
266 local snode = minetest.get_node_or_nil(pos)
268 local sdef = minetest.registered_nodes[snode.name] or {}
269 is_stuck = (sdef.walkable == nil or sdef.walkable == true)
270 and (sdef.collision_box == nil or sdef.collision_box.type == "regular")
271 and (sdef.node_box == nil or sdef.node_box.type == "regular")
274 -- Push item out when stuck inside solid node
278 {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
279 {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
282 -- Check which one of the 4 sides is free
284 local cnode = minetest.get_node(vector.add(pos, order[o])).name
285 local cdef = minetest.registered_nodes[cnode] or {}
286 if cnode ~= "ignore" and cdef.walkable == false then
291 -- If none of the 4 sides is free, check upwards
293 shootdir = {x=0, y=1, z=0}
294 local cnode = minetest.get_node(vector.add(pos, shootdir)).name
295 if cnode == "ignore" then
296 shootdir = nil -- Do not push into ignore
301 -- Set new item moving speed accordingly
302 local newv = vector.multiply(shootdir, 3)
303 self:disable_physics()
304 self.object:set_velocity(newv)
306 self.force_out = newv
307 self.force_out_start = vector.round(pos)
310 elseif self.force_out then
311 -- This code runs after the entity got a push from the above code.
312 -- It makes sure the entity is entirely outside the solid node
313 local c = self.object:get_properties().collisionbox
314 local s = self.force_out_start
315 local f = self.force_out
316 local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
317 (f.y > 0 and pos.y + c[2] > s.y + 0.5) or
318 (f.z > 0 and pos.z + c[3] > s.z + 0.5) or
319 (f.x < 0 and pos.x + c[4] < s.x - 0.5) or
320 (f.z < 0 and pos.z + c[6] < s.z - 0.5)
322 -- Item was successfully forced out
324 self:enable_physics()
328 if not self.physical_state then
329 return -- Don't do anything
332 -- Slide on slippery nodes
333 local vel = self.object:get_velocity()
334 local def = node and minetest.registered_nodes[node.name]
335 local is_moving = (def and not def.walkable) or
336 vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
337 local is_slippery = false
339 if def and def.walkable then
340 local slippery = minetest.get_item_group(node.name, "slippery")
341 is_slippery = slippery ~= 0
342 if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
343 -- Horizontal deceleration
344 local slip_factor = 4.0 / (slippery + 4)
345 self.object:set_acceleration({
346 x = -vel.x * slip_factor,
348 z = -vel.z * slip_factor
350 elseif vel.y == 0 then
355 if self.moving_state == is_moving and
356 self.slippery_state == is_slippery then
357 -- Do not update anything until the moving state changes
361 self.moving_state = is_moving
362 self.slippery_state = is_slippery
365 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
367 self.object:set_acceleration({x = 0, y = 0, z = 0})
368 self.object:set_velocity({x = 0, y = 0, z = 0})