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 local creative_mode = minetest.settings:get_bool("creative_mode")
15 if not creative_mode then
16 function minetest.handle_node_drops(pos, drops, digger)
17 local meta = digger:get_wielded_item():get_meta()
18 local slippery = meta:get_int("slippery")
19 local careful = meta:get_int("careful")
20 local fortune = meta:get_int("fortune") + 1
21 local autorepair = meta:get_int("autorepair")
22 local spiky = meta:get_int("spiky")
24 drops = {minetest.get_node(pos).name}
27 for _,item in ipairs(drops) do
29 if type(item) == "string" then
33 count = item:get_count()
34 name = item:get_name()
37 local obj = minetest.add_item(pos, name)
39 local x=math.random(-2,2)*math.random()
40 local y=math.random(2,5)
41 local z=math.random(-2,2)*math.random()
42 obj:setvelocity({x=x, y=y, z=z})
46 local experience_amount = minetest.get_item_group(minetest.get_node(pos).name,"experience")
47 if experience_amount > 0 then
48 minetest.throw_experience(pos, experience_amount)
51 --make the player drop their "slippery" item
52 if slippery > 0 and math.random(0,1000) < slippery then
53 minetest.item_drop(digger:get_wielded_item(), digger, digger:get_pos())
54 digger:set_wielded_item("")
57 --auto repair the item
58 if autorepair > 0 and math.random(0,1000) < autorepair then
59 local itemstack = digger:get_wielded_item()
60 itemstack:add_wear(autorepair*-100)
61 digger:set_wielded_item(itemstack)
64 --hurt the player randomly
65 if spiky > 0 and math.random(0,1000) < spiky then
66 digger:set_hp(digger:get_hp()-spiky)
71 function minetest.handle_node_drops(pos, drops, digger)
73 minetest.register_on_dignode(function(pos, oldnode, digger)
74 if digger and digger:is_player() then
75 local inv = digger:get_inventory()
76 if inv and not inv:contains_item("main", oldnode) and inv:room_for_item("main", oldnode) then
77 inv:add_item("main", oldnode)
81 minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
82 return(itemstack:get_name())
86 -- Minetest: builtin/item_entity.lua
88 function minetest.spawn_item(pos, item)
89 -- Take item in any format
90 local stack = ItemStack(item)
91 local obj = minetest.add_entity(pos, "__builtin:item")
92 -- Don't use obj if it couldn't be added to the map.
94 obj:get_luaentity():set_item(stack:to_string())
99 function minetest.throw_item(pos, item)
100 -- Take item in any format
101 local stack = ItemStack(item)
102 local obj = minetest.add_entity(pos, "__builtin:item")
103 -- Don't use obj if it couldn't be added to the map.
105 obj:get_luaentity():set_item(stack:to_string())
106 local x=math.random(-2,2)*math.random()
107 local y=math.random(2,5)
108 local z=math.random(-2,2)*math.random()
109 obj:set_velocity({x=x, y=y, z=z})
115 function minetest.throw_experience(pos, amount)
117 local obj = minetest.add_entity(pos, "experience:orb")
118 -- Don't use obj if it couldn't be added to the map.
120 local x=math.random(-2,2)*math.random()
121 local y=math.random(2,5)
122 local z=math.random(-2,2)*math.random()
123 obj:setvelocity({x=x, y=y, z=z})
130 function minetest.item_drop(itemstack, dropper, pos)
131 local dropper_is_player = dropper and dropper:is_player()
132 local p = table.copy(pos)
133 local sneak = dropper:get_player_control().sneak
135 if dropper_is_player then
138 cnt = itemstack:get_count()
143 cnt = itemstack:get_count()
145 local item = itemstack:take_item(cnt)
146 local obj = minetest.add_item(p, item)
148 if dropper_is_player then
149 local dir = dropper:get_look_dir()
151 dir.y = dir.y * 2.9 + 2
153 obj:set_velocity(dir)
154 obj:get_luaentity().dropped_by = dropper:get_player_name()
155 obj:get_luaentity().collection_timer = 0
159 -- If we reach this, adding the object to the
160 -- environment failed
163 -- If item_entity_ttl is not set, enity will have default life time
164 -- Setting it to -1 disables the feature
166 local time_to_live = tonumber(minetest.settings:get("item_entity_ttl")) or 300
167 local gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.81
170 minetest.register_entity(":__builtin:item", {
171 initial_properties = {
174 collide_with_objects = false,
175 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
176 visual = "wielditem",
177 visual_size = {x = 0.4, y = 0.4},
179 spritediv = {x = 1, y = 1},
180 initial_sprite_basepos = {x = 0, y = 0},
187 slippery_state = false,
188 physical_state = true,
191 -- Pushing item out of solid nodes
193 force_out_start = nil,
194 --Collection Variables
195 collection_timer = 2,
196 collection_timer_goal = collection.collection_time,
197 collection_height = collection.collection_height,
202 radius = collection.magnet_radius,
203 time_to_live = time_to_live,
205 set_item = function(self, item)
206 local stack = ItemStack(item or self.itemstring)
207 self.itemstring = stack:to_string()
208 if self.itemstring == "" then
209 -- item not yet known
213 -- Backwards compatibility: old clients use the texture
214 -- to get the type of the item
215 local itemname = stack:is_known() and stack:get_name() or "unknown"
217 local max_count = stack:get_stack_max()
218 local count = math.min(stack:get_count(), max_count)
221 local coll_height = size * 0.75
222 local def = minetest.registered_nodes[itemname]
223 local glow = def and def.light_source
225 self.object:set_properties({
227 visual = "wielditem",
228 textures = {itemname},
229 visual_size = {x = size, y = size},
230 collisionbox = {-size, -0.21, -size,
231 size, coll_height, size},
232 selectionbox = {-size, -size, -size, size, size, size},
233 automatic_rotate = math.pi * 0.5 * 0.2 / size,
234 wield_item = self.itemstring,
240 get_staticdata = function(self)
241 return minetest.serialize({
242 itemstring = self.itemstring,
244 dropped_by = self.dropped_by,
245 collection_timer = self.collection_timer,
246 collectable = self.collectable,
247 try_timer = self.try_timer,
248 collected = self.collected,
249 delete_timer = self.delete_timer,
250 collector = self.collector,
254 on_activate = function(self, staticdata, dtime_s)
255 if string.sub(staticdata, 1, string.len("return")) == "return" then
256 local data = minetest.deserialize(staticdata)
257 if data and type(data) == "table" then
258 self.itemstring = data.itemstring
259 self.age = (data.age or 0) + dtime_s
260 self.dropped_by = data.dropped_by
262 self.collection_timer = data.collection_timer
263 self.collectable = data.collectable
264 self.try_timer = data.try_timer
265 self.collected = data.collected
266 self.delete_timer = data.delete_timer
267 self.collector = data.collector
268 --print("restored timer: "..self.collection_timer)
271 self.itemstring = staticdata
273 local x=math.random(-2,2)*math.random()
274 local y=math.random(2,5)
275 local z=math.random(-2,2)*math.random()
276 self.object:setvelocity(vector.new(x,y,z))
277 -- print(self.collection_timer)
279 self.object:set_armor_groups({immortal = 1})
280 self.object:set_velocity({x = 0, y = 2, z = 0})
281 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
285 enable_physics = function(self)
286 if not self.physical_state then
287 self.physical_state = true
288 self.object:set_properties({physical = true})
289 self.object:set_velocity({x=0, y=0, z=0})
290 self.object:set_acceleration({x=0, y=-gravity, z=0})
294 disable_physics = function(self)
295 if self.physical_state then
296 self.physical_state = false
297 self.object:set_properties({physical = false})
298 self.object:set_velocity({x=0, y=0, z=0})
299 self.object:set_acceleration({x=0, y=0, z=0})
302 on_step = function(self, dtime)
303 --if item set to be collected then only execute go to player
304 if self.collected == true then
305 if not self.collector then
306 self.collected = false
309 local collector = minetest.get_player_by_name(self.collector)
311 self.object:setacceleration(vector.new(0,0,0))
312 self.disable_physics(self)
314 local pos = self.object:getpos()
315 local pos2 = collector:getpos()
316 local player_velocity = collector:get_player_velocity()
317 pos2.y = pos2.y + self.collection_height
319 local direction = vector.normalize(vector.subtract(pos2,pos))
320 local distance = vector.distance(pos2,pos)
323 --remove if too far away
324 if distance > self.radius then
328 local multiplier = (self.radius*5) - distance
329 local velocity = vector.multiply(direction,multiplier)
331 local velocity = vector.add(player_velocity,velocity)
333 self.object:setvelocity(velocity)
335 if distance < 0.2 then
340 --self.delete_timer = self.delete_timer + dtime
341 --this is where the item gets removed from world
342 --if self.delete_timer > 1 then
343 -- self.object:remove()
347 print(self.collector.." does not exist")
352 --allow entity to be collected after timer
353 if self.collectable == false and self.collection_timer >= self.collection_timer_goal then
354 self.collectable = true
355 elseif self.collectable == false then
356 self.collection_timer = self.collection_timer + dtime
359 self.age = self.age + dtime
360 if self.time_to_live > 0 and self.age > self.time_to_live then
366 local pos = self.object:get_pos()
367 local node = minetest.get_node_or_nil({
369 y = pos.y + self.object:get_properties().collisionbox[2] - 0.05,
374 -- Remove nodes in 'ignore'
375 if node and node.name == "ignore" then
381 --burn inside fire nodes
382 local node_inside = minetest.get_node_or_nil(pos)
383 if node_inside and (node_inside.name == "fire:fire" or node_inside.name == "nether:lava" or node_inside.name == "nether:lavaflow" or node_inside.name == "main:lava" or node_inside.name == "main:lavaflow") then
384 minetest.add_particlespawner({
389 minvel = vector.new(-1,0.5,-1),
390 maxvel = vector.new(1,1,1),
391 minacc = {x=0, y=1, z=0},
392 maxacc = {x=0, y=2, z=0},
397 collisiondetection = false,
399 texture = "smoke.png",
401 minetest.sound_play("fire_extinguish", {pos=pos,gain=0.3,pitch=math.random(80,100)/100})
408 local is_stuck = false
409 local snode = minetest.get_node_or_nil(pos)
411 local sdef = minetest.registered_nodes[snode.name] or {}
412 is_stuck = (sdef.walkable == nil or sdef.walkable == true)
413 and (sdef.collision_box == nil or sdef.collision_box.type == "regular")
414 and (sdef.node_box == nil or sdef.node_box.type == "regular")
417 -- Push item out when stuck inside solid node
421 {x=1, y=0, z=0}, {x=-1, y=0, z= 0},
422 {x=0, y=0, z=1}, {x= 0, y=0, z=-1},
425 -- Check which one of the 4 sides is free
427 local cnode = minetest.get_node(vector.add(pos, order[o])).name
428 local cdef = minetest.registered_nodes[cnode] or {}
429 if cnode ~= "ignore" and cdef.walkable == false then
434 -- If none of the 4 sides is free, check upwards
436 shootdir = {x=0, y=1, z=0}
437 local cnode = minetest.get_node(vector.add(pos, shootdir)).name
438 if cnode == "ignore" then
439 shootdir = nil -- Do not push into ignore
444 -- Set new item moving speed accordingly
445 local newv = vector.multiply(shootdir, 3)
446 self:disable_physics()
447 self.object:set_velocity(newv)
449 self.force_out = newv
450 self.force_out_start = vector.round(pos)
453 elseif self.force_out then
454 -- This code runs after the entity got a push from the above code.
455 -- It makes sure the entity is entirely outside the solid node
456 local c = self.object:get_properties().collisionbox
457 local s = self.force_out_start
458 local f = self.force_out
459 local ok = (f.x > 0 and pos.x + c[1] > s.x + 0.5) or
460 (f.y > 0 and pos.y + c[2] > s.y + 0.5) or
461 (f.z > 0 and pos.z + c[3] > s.z + 0.5) or
462 (f.x < 0 and pos.x + c[4] < s.x - 0.5) or
463 (f.z < 0 and pos.z + c[6] < s.z - 0.5)
465 -- Item was successfully forced out
467 self:enable_physics()
471 if not self.physical_state then
472 return -- Don't do anything
475 -- Slide on slippery nodes
476 local vel = self.object:get_velocity()
477 local def = node and minetest.registered_nodes[node.name]
478 local is_moving = (def and not def.walkable) or
479 vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
480 local is_slippery = false
482 if def and def.walkable then
483 local slippery = minetest.get_item_group(node.name, "slippery")
484 is_slippery = slippery ~= 0
485 if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
486 -- Horizontal deceleration
487 local slip_factor = 4.0 / (slippery + 4)
488 self.object:set_acceleration({
489 x = -vel.x * slip_factor,
491 z = -vel.z * slip_factor
493 elseif vel.y == 0 then
496 local collisionbox = self.object:get_properties().collisionbox
497 local move_y = collisionbox[2]
498 if self.move_up == nil then
502 if self.move_up == true then
503 move_y = move_y + (dtime/10)
505 if move_y > -0.21 then
508 elseif self.move_up == false then
509 move_y = move_y - (dtime/10)
510 if move_y < -0.5 then
514 collisionbox[2] = move_y
515 self.object:set_properties({collisionbox=collisionbox,physical = true})
520 if self.moving_state == is_moving and self.slippery_state == is_slippery then
521 -- Do not update anything until the moving state changes
525 self.moving_state = is_moving
526 self.slippery_state = is_slippery
529 self.object:set_acceleration({x = 0, y = -gravity, z = 0})
531 self.object:set_acceleration({x = 0, y = 0, z = 0})
532 self.object:set_velocity({x = 0, y = 0, z = 0})