123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- if not minetest.global_exists("itemburn") then itemburn = {} end
- itemburn.modpath = minetest.get_modpath("itemburn")
- -- Localize for performance.
- local vector_round = vector.round
- local math_random = math.random
- local math_min = math.min
- local abs = math.abs
- local gravity = tonumber(core.settings:get("movement_gravity")) or 9.81
- -- Use an offset for finding the node under the drop,
- -- to allow thin slab shielding for lava, etc.
- itemburn.footstep=-0.25
- function itemburn.get_fs()
- return itemburn.footstep
- end
- -- mods/default/item_entity.lua
- local builtin_item = minetest.registered_entities["__builtin:item"]
- local item = {
- set_item = function(self, itemstring)
- builtin_item.set_item(self, itemstring)
- local stack = ItemStack(itemstring)
- local itemdef = minetest.registered_items[stack:get_name()]
- if itemdef and itemdef.groups.flammable ~= 0 then
- self.flammable = itemdef.groups.flammable
- end
- end,
- -- Copy from builtin, with modifications.
- get_staticdata = function(self)
- return core.serialize({
- itemstring = self.itemstring,
- age = self.age,
- dropped_by = self.dropped_by,
- stuck_arrow = self.stuck_arrow,
- })
- end,
- -- Copy from builtin, with modifications.
- on_activate = function(self, staticdata, dtime_s)
- if string.sub(staticdata, 1, string.len("return")) == "return" then
- local data = core.deserialize(staticdata)
- if data and type(data) == "table" then
- self.itemstring = data.itemstring
- self.age = (data.age or 0) + dtime_s
- self.dropped_by = data.dropped_by
- self.stuck_arrow = data.stuck_arrow
- end
- else
- self.itemstring = staticdata
- end
- self.object:set_armor_groups({immortal = 1})
- -- Leave stuck arrows where they last were.
- if not self.stuck_arrow then
- self.object:set_velocity({x = 0, y = 2, z = 0})
- self.object:set_acceleration({x = 0, y = -gravity, z = 0})
- end
- self._collisionbox = self.initial_properties.collisionbox
- self:set_item()
- if self.stuck_arrow then
- self.object:set_properties({
- automatic_rotate = 0,
- physical = true,
- collide_with_objects = true,
- collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
- })
- end
- end,
- burn_up = function(self, lava)
- -- disappear in a smoke puff
- self.itemstring = ""
- local p = self.object:get_pos()
- minetest.sound_play("default_item_smoke", {
- pos = p,
- max_hear_distance = 8,
- }, true)
- minetest.add_particlespawner({
- amount = 3,
- time = 0.1,
- minpos = {x = p.x - 0.1, y = p.y + 0.1, z = p.z - 0.1 },
- maxpos = {x = p.x + 0.1, y = p.y + 0.2, z = p.z + 0.1 },
- minvel = {x = 0, y = 2.5, z = 0},
- maxvel = {x = 0, y = 2.5, z = 0},
- minacc = {x = -0.15, y = -0.02, z = -0.15},
- maxacc = {x = 0.15, y = -0.01, z = 0.15},
- minexptime = 4,
- maxexptime = 6,
- minsize = 5,
- maxsize = 5,
- collisiondetection = true,
- texture = "default_item_smoke.png"
- })
- if lava then
- local node = minetest.get_node(p)
- lava_extras.spawn_particles(p, node)
- end
- self.object:remove()
- end,
- melt_in_lava = function(self, lpos)
- local p = self.object:get_pos()
- ambiance.sound_play("default_cool_lava", p, 2.0, 16)
- self.itemstring = ""
- self.object:remove()
- local node = minetest.get_node(lpos)
- lava_extras.spawn_particles(lpos, node)
- end,
- on_step = function(self, dtime, moveresult)
- builtin_item.on_step(self, dtime, moveresult)
- local is_falling = false
- local vel = self.object:get_velocity()
- -- Fix spurious error.
- -- Note: documentation explains this is caused by :remove() being called
- -- inside the original on_step() function; see just a few lines above, where
- -- it gets called.
- if not vel then
- return
- end
- if vel.y < -0.1 then
- is_falling = true
- self.need_lava_check = true
- --minetest.chat_send_all("# Server: Falling!")
- end
- if not is_falling and self.need_lava_check then
- --minetest.chat_send_all("# Server: Lava check!")
- local pos = self.object:get_pos()
- local node = minetest.get_node(pos)
- --minetest.chat_send_all("# Server: A=" .. node.name)
- if string.find(node.name, ":lava_") then
- self:melt_in_lava(vector_round(pos))
- return
- else
- local pb = vector_round({x=pos.x, y=pos.y+itemburn.get_fs(), z=pos.z})
- local node = minetest.get_node(pb)
- --minetest.chat_send_all("# Server: U=" .. node.name)
- if string.find(node.name, ":lava_") then
- self:melt_in_lava(pb)
- return
- end
- end
- self.need_lava_check = false
- end
- -- flammable, check for igniters
- self.ignite_timer = (self.ignite_timer or 0) - dtime
- if self.ignite_timer < 0 then
- self.ignite_timer = math_random(10, 100)/10
- local pos = self.object:get_pos()
- local node = minetest.get_node_or_nil(pos)
- if not node then
- return
- end
- -- Immediately burn up flammable items in lava
- if minetest.get_item_group(node.name, "lava") > 0 then
- self:melt_in_lava(vector_round(pos))
- else
- -- Check if sitting on top of lava.
- local pb = vector_round({x=pos.x, y=pos.y+itemburn.get_fs(), z=pos.z})
- local nb = minetest.get_node_or_nil(pb)
- if nb then
- local l = minetest.get_item_group(nb.name, "lava")
- if l > 0 then
- self:melt_in_lava(pb)
- return
- end
- end
- -- otherwise there'll be a chance based on its igniter value
- local burn_chance = (self.flammable or 1) * minetest.get_item_group(node.name, "igniter")
- if burn_chance > 0 and math_random(0, burn_chance) ~= 0 then
- self:burn_up()
- end
- end
- end
- end,
- on_punch = function(self, hitter)
- local inv = hitter:get_inventory()
- if not inv then
- return
- end
- -- Do not allow pickup of items inside fire.
- -- Do not allow pickup of moving items.
- do
- local nn = minetest.get_node(vector.round(self.object:get_pos())).name
- if minetest.get_item_group(nn, "fire") ~= 0 then
- return
- end
- local vel = self.object:get_velocity()
- if abs(vel.x) > 0.01 or abs(vel.y) > 0.01 or abs(vel.z) > 0.01 then
- return
- end
- end
- local clear = true
- if self.itemstring ~= "" then
- local stack = ItemStack(self.itemstring)
- local name = stack:get_name()
- local count = stack:get_count()
- local left
- local index
- local inserted = false
- local newstack
- for i=1, inv:get_size("main"), 1 do
- local s2 = inv:get_stack("main", i)
- local n2 = s2:get_name()
- local empty = s2:is_empty()
- if name == n2 or empty then
- if empty then
- local s3 = stack:take_item(math_min(stack:get_count(), stack:get_stack_max()))
- left = stack
- index = i
- inv:set_stack("main", i, s3)
- newstack = ItemStack(s3) -- A copy of the stack being added.
- inserted = true
- break
- elseif name == n2 and s2:get_free_space() > 0 then
- newstack = ItemStack(stack):take_item(math_min(s2:get_free_space(), stack:get_count())) -- A copy of the stack being added.
- left = s2:add_item(stack)
- index = i
- inv:set_stack("main", i, s2)
- inserted = true
- break
- end
- end
- end
- -- If something was added to the inv, we update the entity, but do not clear it.
- if left and not left:is_empty() then
- count = count - left:get_count()
- self:set_item(left)
- clear = false
- end
- -- If nothing was added to the inventory, we cannot remove the entity.
- if not inserted then
- clear = false
- end
- if inserted then
- minetest.log("action", hitter:get_player_name() .. " picks item-entity " ..
- stack:get_name() .. " " .. count .. " at " .. minetest.pos_to_string(vector_round(self.object:get_pos())))
- -- Execute player inventory callbacks.
- -- Note: inventory callbacks are called when player drops item (Q) so this
- -- implements the reciprocal.
- for _, func in ipairs(core.registered_on_player_inventory_actions) do
- func(hitter, "put", inv, {listname="main", index=index, stack=newstack})
- end
- end
- end
- if clear then
- self.itemstring = ""
- self.object:remove()
- end
- end,
- }
- -- set defined item as new __builtin:item, with the old one as fallback table
- setmetatable(item, builtin_item)
- minetest.register_entity(":__builtin:item", item)
|