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})
34 -- Minetest: builtin/item_entity.lua
36 function minetest.spawn_item(pos, item)
37 -- Take item in any format
38 local stack = ItemStack(item)
39 local obj = minetest.add_entity(pos, "__builtin:item")
40 -- Don't use obj if it couldn't be added to the map.
42 obj:get_luaentity():set_item(stack:to_string())
47 function minetest.throw_item(pos, item)
48 -- Take item in any format
49 local stack = ItemStack(item)
50 local obj = minetest.add_entity(pos, "__builtin:item")
51 -- Don't use obj if it couldn't be added to the map.
53 obj:get_luaentity():set_item(stack:to_string())
54 local x=math.random(-2,2)*math.random()
55 local y=math.random(2,5)
56 local z=math.random(-2,2)*math.random()
57 obj:setvelocity({x=x, y=y, z=z})
63 function minetest.item_drop(itemstack, dropper, pos)
64 local dropper_is_player = dropper and dropper:is_player()
65 local p = table.copy(pos)
66 local cnt = itemstack:get_count()
67 if dropper_is_player then
70 local item = itemstack:take_item(cnt)
71 local obj = minetest.add_item(p, item)
73 if dropper_is_player then
74 local dir = dropper:get_look_dir()
76 dir.y = dir.y * 2.9 + 2
79 obj:get_luaentity().dropped_by = dropper:get_player_name()
80 obj:get_luaentity().collection_timer = 0
84 -- If we reach this, adding the object to the
88 -- If item_entity_ttl is not set, enity will have default life time
89 -- Setting it to -1 disables the feature
91 local time_to_live = tonumber(minetest.settings:get("item_entity_ttl")) or 900
92 local gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.81
95 minetest.register_entity(":__builtin:item", {
96 initial_properties = {
99 collide_with_objects = false,
100 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
101 visual = "wielditem",
102 visual_size = {x = 0.4, y = 0.4},
104 spritediv = {x = 1, y = 1},
105 initial_sprite_basepos = {x = 0, y = 0},
112 slippery_state = false,
113 physical_state = true,
116 -- Pushing item out of solid nodes
118 force_out_start = nil,
119 --Collection Variables
120 collection_timer = 2,
121 collection_timer_goal = collection.collection_time,
122 collection_height = collection.collection_height,
127 radius = collection.magnet_radius,
129 set_item = function(self, item)
130 local stack = ItemStack(item or self.itemstring)
131 self.itemstring = stack:to_string()
132 if self.itemstring == "" then
133 -- item not yet known
137 -- Backwards compatibility: old clients use the texture
138 -- to get the type of the item
139 local itemname = stack:is_known() and stack:get_name() or "unknown"
141 local max_count = stack:get_stack_max()
142 local count = math.min(stack:get_count(), max_count)
145 local coll_height = size * 0.75
146 local def = minetest.registered_nodes[itemname]
147 local glow = def and def.light_source
149 self.object:set_properties({
151 visual = "wielditem",
152 textures = {itemname},
153 visual_size = {x = size, y = size},
154 collisionbox = {-size, -0.21, -size,
155 size, coll_height, size},
156 selectionbox = {-size, -size, -size, size, size, size},
157 automatic_rotate = math.pi * 0.5 * 0.2 / size,
158 wield_item = self.itemstring,
164 get_staticdata = function(self)
165 return minetest.serialize({
166 itemstring = self.itemstring,
168 dropped_by = self.dropped_by,
169 collection_timer = self.collection_timer,
170 collectable = self.collectable,
171 try_timer = self.try_timer,
172 collected = self.collected,
173 delete_timer = self.delete_timer,
174 collector = self.collector,
178 on_activate = function(self, staticdata, dtime_s)
179 if string.sub(staticdata, 1, string.len("return")) == "return" then
180 local data = minetest.deserialize(staticdata)
181 if data and type(data) == "table" then
182 self.itemstring = data.itemstring
183 self.age = (data.age or 0) + dtime_s
184 self.dropped_by = data.dropped_by
186 self.collection_timer = data.collection_timer
187 self.collectable = data.collectable
188 self.try_timer = data.try_timer
189 self.collected = data.collected
190 self.delete_timer = data.delete_timer
191 self.collector = data.collector
192 --print("restored timer: "..self.collection_timer)
195 self.itemstring = staticdata
197 local x=math.random(-2,2)*math.random()
198 local y=math.random(2,5)
199 local z=math.random(-2,2)*math.random()
200 self.object:setvelocity(vector.new(x,y,z))
201 -- print(self.collection_timer)
203 self.object:set_armor_groups({immortal = 1})
204 self.object:set_velocity({x = 0, y = 2, z = 0})
205 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
209 enable_physics = function(self)
210 if not self.physical_state then
211 self.physical_state = true
212 self.object:set_properties({physical = true})
213 self.object:set_velocity({x=0, y=0, z=0})
214 self.object:set_acceleration({x=0, y=-gravity, z=0})
218 disable_physics = function(self)
219 if self.physical_state then
220 self.physical_state = false
221 self.object:set_properties({physical = false})
222 self.object:set_velocity({x=0, y=0, z=0})
223 self.object:set_acceleration({x=0, y=0, z=0})
226 on_step = function(self, dtime)
227 --if item set to be collected then only execute go to player
228 if self.collected == true then
229 if not self.collector then
230 self.collected = false
233 local collector = minetest.get_player_by_name(self.collector)
235 self.object:setacceleration(vector.new(0,0,0))
236 self.disable_physics(self)
238 local pos = self.object:getpos()
239 local pos2 = collector:getpos()
240 local player_velocity = collector:get_player_velocity()
241 pos2.y = pos2.y + self.collection_height
243 local direction = vector.normalize(vector.subtract(pos2,pos))
244 local distance = vector.distance(pos2,pos)
247 --remove if too far away
248 if distance > self.radius then
252 local multiplier = (self.radius*5) - distance
253 local velocity = vector.multiply(direction,multiplier)
255 local velocity = vector.add(player_velocity,velocity)
257 self.object:setvelocity(velocity)
259 if distance < 0.2 then
264 --self.delete_timer = self.delete_timer + dtime
265 --this is where the item gets removed from world
266 --if self.delete_timer > 1 then
267 -- self.object:remove()
271 print(self.collector.." does not exist")
276 --allow entity to be collected after timer
277 if self.collectable == false and self.collection_timer >= self.collection_timer_goal then
278 self.collectable = true
279 elseif self.collectable == false then
280 self.collection_timer = self.collection_timer + dtime
283 self.age = self.age + dtime
284 if time_to_live > 0 and self.age > time_to_live then
290 local pos = self.object:get_pos()
291 local node = minetest.get_node_or_nil({
293 y = pos.y + self.object:get_properties().collisionbox[2] - 0.05,
297 -- Delete in 'ignore' nodes
298 if node and node.name == "ignore" then
304 local is_stuck = false
305 local snode = minetest.get_node_or_nil(pos)
307 local sdef = minetest.registered_nodes[snode.name] or {}
308 is_stuck = (sdef.walkable == nil or sdef.walkable == true)
309 and (sdef.collision_box == nil or sdef.collision_box.type == "regular")
310 and (sdef.node_box == nil or sdef.node_box.type == "regular")
313 -- Push item out when stuck inside solid node
317 {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
318 {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
321 -- Check which one of the 4 sides is free
323 local cnode = minetest.get_node(vector.add(pos, order[o])).name
324 local cdef = minetest.registered_nodes[cnode] or {}
325 if cnode ~= "ignore" and cdef.walkable == false then
330 -- If none of the 4 sides is free, check upwards
332 shootdir = {x=0, y=1, z=0}
333 local cnode = minetest.get_node(vector.add(pos, shootdir)).name
334 if cnode == "ignore" then
335 shootdir = nil -- Do not push into ignore
340 -- Set new item moving speed accordingly
341 local newv = vector.multiply(shootdir, 3)
342 self:disable_physics()
343 self.object:set_velocity(newv)
345 self.force_out = newv
346 self.force_out_start = vector.round(pos)
349 elseif self.force_out then
350 -- This code runs after the entity got a push from the above code.
351 -- It makes sure the entity is entirely outside the solid node
352 local c = self.object:get_properties().collisionbox
353 local s = self.force_out_start
354 local f = self.force_out
355 local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
356 (f.y > 0 and pos.y + c[2] > s.y + 0.5) or
357 (f.z > 0 and pos.z + c[3] > s.z + 0.5) or
358 (f.x < 0 and pos.x + c[4] < s.x - 0.5) or
359 (f.z < 0 and pos.z + c[6] < s.z - 0.5)
361 -- Item was successfully forced out
363 self:enable_physics()
367 if not self.physical_state then
368 return -- Don't do anything
371 -- Slide on slippery nodes
372 local vel = self.object:get_velocity()
373 local def = node and minetest.registered_nodes[node.name]
374 local is_moving = (def and not def.walkable) or
375 vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
376 local is_slippery = false
378 if def and def.walkable then
379 local slippery = minetest.get_item_group(node.name, "slippery")
380 is_slippery = slippery ~= 0
381 if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
382 -- Horizontal deceleration
383 local slip_factor = 4.0 / (slippery + 4)
384 self.object:set_acceleration({
385 x = -vel.x * slip_factor,
387 z = -vel.z * slip_factor
389 elseif vel.y == 0 then
392 local collisionbox = self.object:get_properties().collisionbox
393 local move_y = collisionbox[2]
394 if self.move_up == nil then
398 if self.move_up == true then
399 move_y = move_y + (dtime/10)
401 if move_y > -0.21 then
404 elseif self.move_up == false then
405 move_y = move_y - (dtime/10)
406 if move_y < -0.5 then
410 collisionbox[2] = move_y
411 self.object:set_properties({collisionbox=collisionbox,physical = true})
416 if self.moving_state == is_moving and self.slippery_state == is_slippery then
417 -- Do not update anything until the moving state changes
421 self.moving_state = is_moving
422 self.slippery_state = is_slippery
425 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
427 self.object:set_acceleration({x = 0, y = 0, z = 0})
428 self.object:set_velocity({x = 0, y = 0, z = 0})