123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- if not minetest.global_exists("particles") then particles = {} end
- particles.modpath = minetest.get_modpath("ambiance")
- -- Localize for performance.
- local vector_distance = vector.distance
- local math_random = math.random
- -- Food crumbs when player eats something.
- function ambiance.particles_eat_item(user, name)
- local def = minetest.registered_items[name]
- if not def then
- return
- end
- local texture = ""
- if def.inventory_image then
- texture = def.inventory_image
- elseif def.wield_image then
- texture = def.wield_image
- end
- if texture == "" then
- return
- end
- local rnd = function(u, l)
- return math_random(u*10, l*10)/10
- end
- local pos = user:get_pos()
- local yaw = user:get_look_horizontal()
- local forward = vector.multiply(minetest.yaw_to_dir(yaw), 0.3)
- local push = vector.multiply(minetest.yaw_to_dir(yaw), 1.5)
- pos = vector.add(pos, forward)
- local particles = {
- amount = math_random(2, 5),
- time = 0.2,
- minpos = vector.add(pos, {x=-0.1, y=1.1, z=-0.1}),
- maxpos = vector.add(pos, {x=0.1, y=1.6, z=0.1}),
- minvel = vector.add(vector.new(-0.3, 0.3, -0.3), push),
- maxvel = vector.add(vector.new(0.3, 0.6, 0.3), push),
- minacc = vector.new(0.0, -8.0, 0.0),
- maxacc = vector.new(0.0, -8.0, 0.0),
- minexptime = 0.5,
- maxexptime = 2,
- minsize = 0.8,
- maxsize = 1.3,
- collisiondetection = true,
- collision_removal = true,
- vertical = false,
- texture = texture,
- }
- minetest.add_particlespawner(particles)
- end
- -- Particles when player is entirely submerged.
- function ambiance.particles_underwater(pos)
- local rnd = function(u, l)
- return math_random(u*10, l*10)/10
- end
- local particles = {
- amount = math_random(5, 10),
- time = 1.0,
- minpos = vector.add(pos, -0.5),
- maxpos = vector.add(pos, 0.5),
- minvel = vector.new(0.5, 0.5, 0.5),
- maxvel = vector.new(-0.5, -0.5, -0.5),
- minacc = vector.new(0.1, 0.1, 0.1),
- maxacc = vector.new(-0.1, -0.1, -0.1),
- minexptime = 0.5,
- maxexptime = 2,
- minsize = 0.1,
- maxsize = 1.0,
- collisiondetection = false,
- collision_removal = false,
- vertical = false,
- texture = "default_water.png",
- }
- minetest.add_particlespawner(particles)
- end
- -- Swimming particles when player is swimming on water surface.
- function ambiance.particles_swimming(pos)
- local rnd = function(u, l)
- return math_random(u*10, l*10)/10
- end
- local bubbles = {
- amount = math_random(5, 10),
- time = 1.0,
- minpos = vector.add(pos, -0.5),
- maxpos = vector.add(pos, 0.5),
- minvel = vector.new(-0.5, 0.0, -0.5),
- maxvel = vector.new(0.5, 0.5, 0.5),
- minacc = vector.new(0.0, -6, 0.0),
- maxacc = vector.new(0.0, -10, 0.0),
- minexptime = 0.5,
- maxexptime = 2,
- minsize = 0.5,
- maxsize = 1.5,
- collisiondetection = false,
- collision_removal = false,
- vertical = false,
- texture = "bubble.png",
- }
- minetest.add_particlespawner(bubbles)
- local splash = {
- amount = math_random(5, 10),
- time = 1.0,
- minpos = vector.add(pos, -0.5),
- maxpos = vector.add(pos, 0.5),
- minvel = vector.new(-0.5, 0.0, -0.5),
- maxvel = vector.new(0.5, 0.5, 0.5),
- minacc = vector.new(0.0, -6, 0.0),
- maxacc = vector.new(0.0, -10, 0.0),
- minexptime = 0.5,
- maxexptime = 2,
- minsize = 0.1,
- maxsize = 1.0,
- collisiondetection = false,
- collision_removal = false,
- vertical = false,
- texture = "default_water.png",
- }
- minetest.add_particlespawner(splash)
- end
- local function get_texture(node)
- local texture = ""
- local def = minetest.registered_items[node.name]
- if def then
- if def.tiles and def.tiles[1] then
- if type(def.tiles[1]) == "string" then
- texture = def.tiles[1]
- end
- end
- end
- -- If no texture could be found, calling function should abort.
- return texture
- end
- function ambiance.particles_on_dig(pos, node)
- local texture = get_texture(node)
- if texture == "" then
- return
- end
- local particles = {
- amount = math_random(5, 10),
- time = 0.1,
- minpos = vector.add(pos, -0.49),
- maxpos = vector.add(pos, 0.49),
- minvel = {x=0, y=1, z=0},
- maxvel = {x=0, y=2, z=0},
- minacc = {x=0, y=-10, z=0},
- maxacc = {x=0, y=-10, z=0},
- minexptime = 0.5,
- maxexptime = 1,
- minsize = 1,
- maxsize = 1,
- collisiondetection = true,
- collision_removal = false,
- vertical = false,
- texture = texture,
- }
- minetest.add_particlespawner(particles)
- end
- function ambiance.particles_on_punch(pos, node)
- local texture = get_texture(node)
- if texture == "" then
- return
- end
- local particles = {
- amount = math_random(1, 5),
- time = 0.1,
- minpos = vector.add(pos, -0.49),
- maxpos = vector.add(pos, 0.49),
- minvel = {x=-0.3, y=0, z=-0.3},
- maxvel = {x=0.3, y=0, z=0.3},
- minacc = {x=0, y=-10, z=0},
- maxacc = {x=0, y=-10, z=0},
- minexptime = 0.5,
- maxexptime = 1,
- minsize = 1,
- maxsize = 1,
- collisiondetection = true,
- collision_removal = false,
- vertical = false,
- texture = texture,
- }
- minetest.add_particlespawner(particles)
- end
- function ambiance.particles_on_place(pos, node)
- local texture = get_texture(node)
- if texture == "" then
- return
- end
- local particles = {
- amount = math_random(5, 10),
- time = 0.1,
- minpos = vector.add(pos, -0.49),
- maxpos = vector.add(pos, 0.49),
- minvel = {x=-0.3, y=0, z=-0.3},
- maxvel = {x=0.3, y=0, z=0.3},
- minacc = {x=0, y=-10, z=0},
- maxacc = {x=0, y=-10, z=0},
- minexptime = 0.5,
- maxexptime = 1,
- minsize = 1,
- maxsize = 1,
- collisiondetection = true,
- collision_removal = false,
- vertical = false,
- texture = texture,
- }
- minetest.add_particlespawner(particles)
- end
- local function player_nearby(pos)
- local players = minetest.get_connected_players()
- for k, v in ipairs(players) do
- if vector_distance(pos, v:get_pos()) < 16 then
- return true
- end
- end
- end
- function ambiance.flamespawner(self, dtime)
- self.st = (self.st or 0) - dtime
- self.ct = (self.ct or 0) - dtime
- self.nt = (self.nt or 0) - dtime
- -- Remove spawner if no flame here.
- if self.nt < 0 then
- self.nt = math_random(10, 60)
- local pos = self.object:get_pos()
- local nn = minetest.get_node(pos).name
- if not string.find(nn, "^fire:") and not string.find(nn, "^maptools:") then
- self.object:remove()
- return
- end
- end
- -- Check every so often if a player is nearby.
- if self.ct < 0 then
- local pos = self.object:get_pos()
- self.good = player_nearby(pos)
- self.ct = math_random(2, 8)
- end
- if self.st < 0 then
- local rnd = function(u, l)
- return math_random(u*10, l*10)/10
- end
- self.st = rnd(0.5, 1.0)
- -- Spawn particle only if player nearby.
- if self.good then
- local pos = self.object:get_pos()
- local particle = {
- pos = {x=pos.x+rnd(-0.5, 0.5), y=pos.y+rnd(0.0, 0.5), z=pos.z+rnd(-0.5, 0.5)},
- velocity = {x=rnd(-0.1, 0.1), y=rnd(0.1, 0.7), z=rnd(-0.1, 0.1)},
- acceleration = {x=rnd(-0.1, 0.1), y=rnd(0.1, 0.7), z=rnd(-0.1, 0.1)},
- expirationtime = rnd(0.1, 2.0),
- size = rnd(0.3, 0.7),
- collisiondetection = false,
- collision_removal = false,
- vertical = false,
- texture = "particles.png",
- animation = {
- type = "vertical_frames",
- aspect_w = 1,
- aspect_h = 1,
- length = 1.0,
- },
- glow = rnd(10, 15),
- }
- if math_random(1, 6) == 1 then
- particle.texture = "smoke_particles.png"
- particle.animation = {
- type = "vertical_frames",
- aspect_w = 4,
- aspect_h = 4,
- length = 1.0,
- }
- particle.size = rnd(0.8, 1.1)
- particle.velocity.y = particle.velocity.y + rnd(0.2, 0.4)
- particle.pos.y = pos.y + rnd(0.4, 0.6)
- end
- minetest.add_particle(particle)
- -- Occasionally play flame sound.
- if math_random(1, 10) == 1 then
- ambiance.sound_play("fire_small", pos, 0.3, 16)
- end
- end
- end
- end
- function particles.add_flame_spawner(pos)
- minetest.add_entity(pos, "particles:flamespawner")
- end
- function particles.del_flame_spawner(pos)
- local ents = minetest.get_objects_inside_radius(pos, 0.6)
- if ents then
- for k, obj in ipairs(ents) do
- if obj and obj:get_luaentity() and obj:get_luaentity().name == "particles:flamespawner" then
- obj:remove()
- end
- end
- end
- end
- function particles.restore_flame_spawner(pos)
- particles.del_flame_spawner(pos)
- particles.add_flame_spawner(pos)
- end
- if not particles.run_once then
- -- File is reloadable.
- local c = "particles:core"
- local f = particles.modpath .. "/particles.lua"
- reload.register_file(c, f, false)
- -- Torches no longer spawn particles, this creates too many entities and network packets.
- -- The entity definition now only exists to delete existing torchspawners from the world.
- local torchspawner = {
- visual = "wielditem",
- visual_size = {x=0, y=0},
- collisionbox = {0, 0, 0, 0, 0, 0},
- physical = false,
- textures = {"air"},
- is_visible = false,
- on_activate = function(self, staticdata, dtime_s)
- self.object:remove()
- end,
- on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
- end,
- on_death = function(self, killer)
- end,
- on_rightclick = function(self, clicker)
- end,
- get_staticdata = function(self)
- return ""
- end,
- on_step = function(self, dtime)
- self.object:remove()
- end,
- }
- minetest.register_entity(":particles:torchspawner", torchspawner)
- local flamespawner = {
- visual = "wielditem",
- visual_size = {x=0, y=0},
- collisionbox = {0, 0, 0, 0, 0, 0},
- physical = false,
- textures = {"air"},
- is_visible = false,
- on_activate = function(self, staticdata, dtime_s)
- end,
- on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
- end,
- on_death = function(self, killer)
- end,
- on_rightclick = function(self, clicker)
- end,
- get_staticdata = function(self)
- return ""
- end,
- on_step = function(self, dtime)
- return ambiance.flamespawner(self, dtime)
- end,
- }
- minetest.register_entity(":particles:flamespawner", flamespawner)
- particles.run_once = true
- end
|