Compare commits

...

10 Commits

Author SHA1 Message Date
cora c711380064 reimplement basic minecraft like fire spread 2022-01-15 03:31:15 +01:00
cora b1189433a4 make nodes actually be removed by the fire 2022-01-15 01:00:25 +01:00
cora 2ef8f788c2 Add node timer back in so fires burn out lol 2022-01-14 23:01:12 +01:00
cora 7375cc0706 replace laggy mcl fire with mtg abms 2022-01-14 22:15:44 +01:00
cora 22ec7a65d8 optimize nether porticles 2022-01-14 18:15:11 +01:00
Lizzy Fleckenstein 4cfb65003b Fix reference dupes for droppers and dispensers 2022-01-14 18:15:11 +01:00
Lizzy Fleckenstein 5060e600d7 Fix reference dupe glitches 2022-01-14 18:15:11 +01:00
Lizzy Fleckenstein 20900cccd5 Fix anvil duplication glitch 2022-01-14 18:15:11 +01:00
Lizzy Fleckenstein 51f3869ffe Fix another anvil weirdness and dupe glitch 2022-01-14 18:15:11 +01:00
cora 89d63080be replace nether dust particles with p. spawners
mineclonia uses add_particle for nether dust resulting in a 10-fold
increase in network traffic when in the nether. Nether dust is not
configurable making it impossible to turn this off for server admins.
this commit replaces the add_particle method with particle spawners
2022-01-14 18:15:06 +01:00
11 changed files with 276 additions and 326 deletions

View File

@ -1,36 +1,66 @@
mcl_weather.nether_dust = {}
mcl_weather.nether_dust.particles_count = 99
mcl_weather.nether_dust.particlespawners = {}
-- calculates coordinates and draw particles for Nether dust
mcl_weather.nether_dust.add_dust_particles = function(player)
for i=mcl_weather.nether_dust.particles_count, 1,-1 do
local rpx, rpy, rpz = mcl_weather.get_random_pos_by_player_look_dir(player)
minetest.add_particle({
pos = {x = rpx, y = rpy - math.random(6, 18), z = rpz},
velocity = {x = math.random(-30,30)*0.01, y = math.random(-15,15)*0.01, z = math.random(-30,30)*0.01},
acceleration = {x = math.random(-50,50)*0.02, y = math.random(-20,20)*0.02, z = math.random(-50,50)*0.02},
expirationtime = 3,
size = math.random(6,20)*0.01,
collisiondetection = false,
object_collision = false,
vertical = false,
glow = math.random(0,minetest.LIGHT_MAX),
texture = "mcl_particles_nether_dust"..tostring(i%3+1)..".png",
playername = player:get_player_name()
})
local psdef= {
amount = 150,
time = 0,
minpos = vector.new(-15,-15,-15),
maxpos =vector.new(15,15,15),
minvel = vector.new(-0.3,-0.15,-1),
maxvel = vector.new(0.3,0.15,0.3),
minacc = vector.new(-1,-0.4,-1),
maxacc = vector.new(1,0.4,1),
minexptime = 1,
maxexptime = 10,
minsize = 0.2,
maxsize = 0.7,
collisiondetection = false,
collision_removal = false,
object_collision = false,
vertical = false
}
local function check_player(player)
local name=player:get_player_name()
if mcl_worlds.has_dust(player:get_pos()) and not mcl_weather.nether_dust.particlespawners[name] then
return true
end
end
mcl_weather.nether_dust.add_particlespawners = function(player)
local name=player:get_player_name(name)
mcl_weather.nether_dust.particlespawners[name]={}
psdef.playername = name
psdef.attached = player
psdef.glow = math.random(0,minetest.LIGHT_MAX)
for i=1,3 do
psdef.texture="mcl_particles_nether_dust"..i..".png"
mcl_weather.nether_dust.particlespawners[name][i]=minetest.add_particlespawner(psdef)
end
end
local timer = 0
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer < 0.7 then return end
timer = 0
for _, player in ipairs(minetest.get_connected_players()) do
if not mcl_worlds.has_dust(player:get_pos()) then
return false
mcl_weather.nether_dust.delete_particlespawners = function(player)
local name=player:get_player_name(name)
if mcl_weather.nether_dust.particlespawners[name] then
for i=1,3 do
minetest.delete_particlespawner(mcl_weather.nether_dust.particlespawners[name][i])
end
mcl_weather.nether_dust.add_dust_particles(player)
mcl_weather.nether_dust.particlespawners[name]=nil
end
end
mcl_worlds.register_on_dimension_change(function(player, dimension)
if check_player(player) then
return mcl_weather.nether_dust.add_particlespawners(player)
end
mcl_weather.nether_dust.delete_particlespawners(player)
end)
minetest.register_on_joinplayer(function(player)
if check_player(player) then
mcl_weather.nether_dust.add_particlespawners(player)
end
end)
minetest.register_on_leaveplayer(function(player)
mcl_weather.nether_dust.delete_particlespawners(player)
end)

View File

@ -82,7 +82,7 @@ local dispenserdef = {
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
local inv = meta:get_inventory()
for i=1, inv:get_size("main") do
@ -92,7 +92,7 @@ local dispenserdef = {
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
_mcl_blast_resistance = 3.5,
_mcl_hardness = 3.5,

View File

@ -55,7 +55,7 @@ local dropperdef = {
sounds = mcl_sounds.node_sound_stone_defaults(),
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
local inv = meta:get_inventory()
for i=1, inv:get_size("main") do
@ -65,7 +65,7 @@ local dropperdef = {
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
local name = player:get_player_name()

View File

@ -53,7 +53,7 @@ local dropperdef = {
sounds = mcl_sounds.node_sound_stone_defaults(),
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
local inv = meta:get_inventory()
for i=1, inv:get_size("main") do
@ -63,7 +63,7 @@ local dropperdef = {
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
local name = player:get_player_name()

View File

@ -101,14 +101,14 @@ local function update_anvil_slots(meta)
end
local can_combine = mcl_enchanting.combine(input1, input2)
if can_combine then
-- Add tool health together plus a small bonus
if def1.type == "tool" and def2.type == "tool" then
local new_wear = calculate_repair(input1:get_wear(), input2:get_wear(), SAME_TOOL_REPAIR_BOOST)
input1:set_wear(new_wear)
end
name_item = input1
new_output = name_item
-- Tool + repair item
@ -318,11 +318,11 @@ local anvildef = {
_mcl_after_falling = damage_anvil_by_falling,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta = minetest.get_meta(pos)
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
drop_anvil_items(pos, meta)
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local name = player:get_player_name()

View File

@ -346,7 +346,7 @@ end
local drop_items_chest = function(pos, oldnode, oldmetadata)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
if oldmetadata then
meta:from_table(oldmetadata)
end
@ -358,7 +358,7 @@ local drop_items_chest = function(pos, oldnode, oldmetadata)
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end
local on_chest_blast = function(pos)

View File

@ -23,7 +23,7 @@ end
function mcl_enchanting.load_enchantments(itemstack, enchantments)
if not mcl_enchanting.is_book(itemstack:get_name()) then
mcl_enchanting.unload_enchantments(itemstack)
mcl_enchanting.unload_enchantments(itemstack)
for enchantment, level in pairs(enchantments or mcl_enchanting.get_enchantments(itemstack)) do
local enchantment_def = mcl_enchanting.enchantments[enchantment]
if enchantment_def.on_enchant then
@ -160,7 +160,7 @@ function mcl_enchanting.combine(itemstack, combine_with)
local itemname = itemstack:get_name()
local combine_name = combine_with:get_name()
local enchanted_itemname = mcl_enchanting.get_enchanted_itemstring(itemname)
if enchanted_itemname ~= mcl_enchanting.get_enchanted_itemstring(combine_name) and not mcl_enchanting.is_book(combine_name) then
if not enchanted_itemname or enchanted_itemname ~= mcl_enchanting.get_enchanted_itemstring(combine_name) and not mcl_enchanting.is_book(combine_name) then
return false
end
local enchantments = mcl_enchanting.get_enchantments(itemstack)

View File

@ -5,29 +5,6 @@ mcl_fire = {}
local S = minetest.get_translator("mcl_fire")
local N = function(s) return s end
-- inverse pyramid pattern above lava source, floor 1 of 2:
local lava_fire=
{
{ x =-1, y = 1, z =-1},
{ x =-1, y = 1, z = 0},
{ x =-1, y = 1, z = 1},
{ x = 0, y = 1, z =-1},
{ x = 0, y = 1, z = 0},
{ x = 0, y = 1, z = 1},
{ x = 1, y = 1, z =-1},
{ x = 1, y = 1, z = 0},
{ x = 1, y = 1, z = 1}
}
local alldirs=
{
{ x =-1, y = 0, z = 0},
{ x = 1, y = 0, z = 0},
{ x = 0, y =-1, z = 0},
{ x = 0, y = 1, z = 0},
{ x = 0, y = 0, z =-1},
{ x = 0, y = 0, z = 1}
}
local spawn_smoke = function(pos)
mcl_particles.add_node_particlespawner(pos, {
amount = 0.1,
@ -85,15 +62,15 @@ local fire_death_messages = {
N("@1 died in a fire."),
}
local fire_timer = function(pos)
minetest.get_node_timer(pos):start(math.random(3, 7))
end
local spawn_fire = function(pos, age)
minetest.set_node(pos, {name="mcl_fire:fire", param2 = age})
minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z})
end
local function fire_timer(pos)
return minetest.get_node_timer(pos):start(math.random(30, 60))
end
minetest.register_node("mcl_fire:fire", {
description = S("Fire"),
_doc_items_longdesc = fire_help,
@ -124,84 +101,16 @@ minetest.register_node("mcl_fire:fire", {
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end
end,
on_timer = function(pos)
local node = minetest.get_node(pos)
-- Age is a number from 0 to 15 and is increased every timer step.
-- "old" fire is more likely to be extinguished
local age = node.param2
local flammables = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
local below = minetest.get_node({x=pos.x, y=pos.z-1, z=pos.z})
local below_is_flammable = minetest.get_item_group(below.name, "flammable") > 0
-- Extinguish fire
if (not fire_enabled) and (math.random(1,3) == 1) then
minetest.remove_node(pos)
return
end
if age == 15 and not below_is_flammable then
minetest.remove_node(pos)
return
elseif age > 3 and #flammables == 0 and not below_is_flammable and math.random(1,4) == 1 then
minetest.remove_node(pos)
return
end
local age_add = 1
-- If fire spread is disabled, we have to skip the "destructive" code
if (not fire_enabled) then
if age + age_add <= 15 then
node.param2 = age + age_add
minetest.set_node(pos, node)
end
-- Restart timer
fire_timer(pos)
return
end
-- Spawn fire to nearby flammable nodes
local is_next_to_flammable = minetest.find_node_near(pos, 2, {"group:flammable"}) ~= nil
if is_next_to_flammable and math.random(1,2) == 1 then
-- The fire we spawn copies the age of this fire.
-- This prevents fire from spreading infinitely far as the fire fire dies off
-- quicker the further it has spreaded.
local age_next = math.min(15, age + math.random(0, 1))
-- Select random type of fire spread
local burntype = math.random(1,2)
if burntype == 1 then
-- Spawn fire in air
local nodes = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
while #nodes > 0 do
local r = math.random(1, #nodes)
if minetest.find_node_near(nodes[r], 1, {"group:flammable"}) then
spawn_fire(nodes[r], age_next)
break
else
table.remove(nodes, r)
end
end
else
-- Burn flammable block
local nodes = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
if #nodes > 0 then
local r = math.random(1, #nodes)
local nn = minetest.get_node(nodes[r]).name
local ndef = minetest.registered_nodes[nn]
local fgroup = minetest.get_item_group(nn, "flammable")
if ndef and ndef._on_burn then
ndef._on_burn(nodes[r])
elseif fgroup ~= -1 then
spawn_fire(nodes[r], age_next)
end
end
end
end
-- Regular age increase
if age + age_add <= 15 then
node.param2 = age + age_add
minetest.set_node(pos, node)
end
-- Restart timer
fire_timer(pos)
end,
drop = "",
sounds = {},
on_timer= function(pos)
if not minetest.find_node_near(pos, 1, {"group:flammable"}) then
minetest.remove_node(pos)
return
end
-- Restart timer
return true
end,
-- Turn into eternal fire on special blocks, light Nether portal (if possible), start burning timer
on_construct = function(pos)
local bpos = {x=pos.x, y=pos.y-1, z=pos.z}
@ -215,9 +124,8 @@ minetest.register_node("mcl_fire:fire", {
if minetest.get_modpath("mcl_portals") then
mcl_portals.light_nether_portal(pos)
end
fire_timer(pos)
spawn_smoke(pos)
fire_timer(pos)
end,
on_destruct = function(pos)
mcl_particles.delete_node_particlespawners(pos)
@ -255,29 +163,7 @@ minetest.register_node("mcl_fire:eternal_fire", {
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end
end,
on_timer = function(pos)
if fire_enabled then
local airs = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
while #airs > 0 do
local r = math.random(1, #airs)
if minetest.find_node_near(airs[r], 1, {"group:flammable"}) then
local node = minetest.get_node(airs[r])
local age = node.param2
local age_next = math.min(15, age + math.random(0, 1))
spawn_fire(airs[r], age_next)
break
else
table.remove(airs, r)
end
end
end
-- Restart timer
fire_timer(pos)
end,
-- Start burning timer and light Nether portal (if possible)
on_construct = function(pos)
fire_timer(pos)
if minetest.get_modpath("mcl_portals") then
mcl_portals.light_nether_portal(pos)
end
@ -402,114 +288,6 @@ if flame_sound then
end
--
-- ABMs
--
-- Extinguish all flames quickly with water and such
minetest.register_abm({
label = "Extinguish fire",
nodenames = {"mcl_fire:fire", "mcl_fire:eternal_fire"},
neighbors = {"group:puts_out_fire"},
interval = 3,
chance = 1,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
minetest.remove_node(pos)
minetest.sound_play("fire_extinguish_flame",
{pos = pos, max_hear_distance = 16, gain = 0.15}, true)
end,
})
-- Enable the following ABMs according to 'enable fire' setting
local function has_flammable(pos)
local npos, node
for n, v in ipairs(alldirs) do
npos = vector.add(pos, v)
node = minetest.get_node_or_nil(npos)
if node and node.name and minetest.get_item_group(node.name, "flammable") ~= 0 then
return npos
end
end
return false
end
if not fire_enabled then
-- Occasionally remove fire if fire disabled
-- NOTE: Fire is normally extinguished in timer function
minetest.register_abm({
label = "Remove disabled fire",
nodenames = {"mcl_fire:fire"},
interval = 10,
chance = 10,
catch_up = false,
action = minetest.remove_node,
})
else -- Fire enabled
-- Set fire to air nodes
minetest.register_abm({
label = "Ignite fire by lava",
nodenames = {"group:lava"},
neighbors = {"air"},
interval = 7,
chance = 3,
catch_up = false,
action = function(pos)
local i, dir, target, node, i2, f
i = math.random(1,9)
dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
node = minetest.get_node(target)
if not node or node.name ~= "air" then
i = ((i + math.random(0,7)) % 9) + 1
dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
node = minetest.get_node(target)
if not node or node.name ~= "air" then
return
end
end
i2 = math.random(1,15)
if i2 < 10 then
local dir2, target2, node2
dir2 = lava_fire[i2]
target2 = {x=target.x+dir2.x, y=target.y+dir2.y, z=target.z+dir2.z}
node2 = minetest.get_node(target2)
if node2 and node2.name == "air" then
f = has_flammable(target2)
if f then
minetest.after(1, spawn_fire, {x=target2.x, y=target2.y, z=target2.z})
minetest.add_particle({
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.7), z=f.z-pos.z},
expirationtime=1, size=1.5, collisiondetection=false,
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
})
return
end
end
end
f = has_flammable(target)
if f then
minetest.after(1, spawn_fire, {x=target.x, y=target.y, z=target.z})
minetest.add_particle({
pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}),
velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.25), z=f.z-pos.z},
expirationtime=1, size=1, collisiondetection=false,
glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png"
})
end
end,
})
end
-- Set pointed_thing on (normal) fire.
-- * pointed_thing: Pointed thing to ignite
-- * player: Player who sets fire or nil if nobody
@ -535,6 +313,125 @@ mcl_fire.set_fire = function(pointed_thing, player, allow_on_fire)
end
end
--
-- ABMs
--
-- Extinguish all flames quickly with water and such
minetest.register_abm({
label = "Extinguish fire",
nodenames = {"mcl_fire:fire", "mcl_fire:eternal_fire"},
neighbors = {"group:puts_out_fire"},
interval = 3,
chance = 1,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
minetest.remove_node(pos)
minetest.sound_play("fire_extinguish_flame",
{pos = pos, max_hear_distance = 16, gain = 0.15}, true)
end,
})
-- Enable the following ABMs according to 'enable fire' setting
-- [...]a fire that is not adjacent to any flammable block does not spread, even to another flammable block within the normal range.
-- https://minecraft.fandom.com/wiki/Fire#Spread
local function has_flammable(pos)
return minetest.find_node_near(pos, 1, {"group:flammable"})
end
local function check_aircube(p1,p2)
local nds=minetest.find_nodes_in_area(p1,p2,{"air"})
for k,v in pairs(nds) do
if has_flammable(v) then return v end
end
end
-- [...] a fire block can turn any air block that is adjacent to a flammable block into a fire block. This can happen at a distance of up to one block downward, one block sideways (including diagonals), and four blocks upward of the original fire block (not the block the fire is on/next to).
local function get_ignitable(pos)
return check_aircube(vector.add(pos,vector.new(-1,-1,-1)),vector.add(pos,vector.new(1,4,1)))
end
-- Fire spreads from a still lava block similarly: any air block one above and up to one block sideways (including diagonals) or two above and two blocks sideways (including diagonals) that is adjacent to a flammable block may be turned into a fire block.
local function get_ignitable_by_lava(pos)
return check_aircube(vector.add(pos,vector.new(-1,1,-1)),vector.add(pos,vector.new(1,1,1))) or check_aircube(vector.add(pos,vector.new(-2,2,-2)),vector.add(pos,vector.new(2,2,2))) or nil
end
if not fire_enabled then
-- Occasionally remove fire if fire disabled
-- NOTE: Fire is normally extinguished in timer function
minetest.register_abm({
label = "Remove disabled fire",
nodenames = {"mcl_fire:fire"},
interval = 10,
chance = 10,
catch_up = false,
action = minetest.remove_node,
})
else -- Fire enabled
-- Fire Spread
minetest.register_abm({
label = "Ignite flame",
nodenames ={"mcl_fire:fire","mcl_fire:eternal_fire"},
interval = 7,
chance = 12,
catch_up = false,
action = function(pos)
local p = get_ignitable(pos)
if p then
minetest.set_node(p, {name = "mcl_fire:fire"})
end
end
})
--lava fire spread
minetest.register_abm({
label = "Ignite fire by lava",
nodenames = {"mcl_core:lava_source","mcl_nether:nether_lava_source"},
neighbors = {"air","group:flammable"},
interval = 7,
chance = 3,
catch_up = false,
action = function(pos)
local p=get_ignitable_by_lava(pos)
if p then
minetest.set_node(p, {name = "mcl_fire:fire"})
end
end,
})
-- Remove flammable nodes around basic flame
minetest.register_abm({
label = "Remove flammable nodes",
nodenames = {"mcl_fire:fire","mcl_fire:eternal_fire"},
neighbors = {"group:flammable"},
interval = 5,
chance = 18,
catch_up = false,
action = function(pos)
local p = minetest.find_node_near(pos, 1, {"group:flammable"})
if not p then
return
end
local flammable_node = minetest.get_node(p)
local def = minetest.registered_nodes[flammable_node.name]
if def.on_burn then
def.on_burn(p)
else
minetest.swap_node(p, {name = "mcl_fire:fire"})
fire_timer(p)
minetest.check_for_falling(p)
end
end
})
end
minetest.register_lbm({
label = "Smoke particles from fire",
name = "mcl_fire:smoke",

View File

@ -451,7 +451,7 @@ minetest.register_node("mcl_furnaces:furnace", {
on_timer = furnace_node_timer,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
local inv = meta:get_inventory()
for _, listname in ipairs({"src", "dst", "fuel"}) do
@ -461,7 +461,7 @@ minetest.register_node("mcl_furnaces:furnace", {
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
on_construct = function(pos)

View File

@ -61,7 +61,7 @@ local def_hopper = {
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
local inv = meta:get_inventory()
for i=1,inv:get_size("main") do
@ -71,7 +71,7 @@ local def_hopper = {
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
local name = player:get_player_name()

View File

@ -29,6 +29,9 @@ if minetest.features.use_texture_alpha_string_modes then
PORTAL_ALPHA = nil
end
local PORTICLE_DISTANCE = 15 --how far to send particle spawners for the portalnodes
local porticlespawners = {}
-- Table of objects (including players) which recently teleported by a
-- Nether portal. Those objects have a brief cooloff period before they
-- can teleport again. This prevents annoying back-and-forth teleportation.
@ -59,6 +62,65 @@ local function nether_to_overworld(x)
return LIMIT - math.abs(((x * OVERWORLD_TO_NETHER_SCALE + LIMIT) % (LIMIT*4)) - (LIMIT*2))
end
local function remove_particlespawner_at_position(playername,pos)
if not porticlespawners[minetest.pos_to_string(pos)] or porticlespawners[minetest.pos_to_string(pos)][playername] == nil then return end
minetest.delete_particlespawner(porticlespawners[minetest.pos_to_string(pos)][playername],playername)
porticlespawners[minetest.pos_to_string(pos)][playername]=nil
end
local function add_particlespawner_at_position(player,pos,node)
if not porticlespawners[minetest.pos_to_string(pos)] then porticlespawners[minetest.pos_to_string(pos)] = {} end
if porticlespawners[minetest.pos_to_string(pos)][player:get_player_name()] ~= nil then return end
porticlespawners[minetest.pos_to_string(pos)][player:get_player_name()]=minetest.add_particlespawner({
amount = node_particles_allowed_level + 1,
minpos = vector.add(pos, vector.new(-3,-3,-3)),
maxpos = vector.add(pos, vector.new(3,3,3)),
minvel = vector.new(-0.5,-0.5,-0.5),
maxvel = vector.new(0.5,0.5,0.5),
minacc = vector.new(-0.5,-0.5,-0.5),
maxacc = vector.new(0.5,0.5,0.5),
minexptime = 0.1,
maxexptime = 2.4,
minsize = 0.3,
maxsize = 1.8,
time=0,
collisiondetection = false,
texture = "mcl_particles_nether_portal.png",
playername = player:get_player_name(),
})
end
local function add_porticlespawners(pos,node)
--Add particlespawners for all players in range
for _,obj in pairs(minetest.get_connected_players()) do
if vector.distance(obj:get_pos(),pos) <= PORTICLE_DISTANCE then
add_particlespawner_at_position(obj,pos,node)
end
end
end
local function remove_porticlespawners(pos,force)
--Remove particlespawners for all players out of range
-- force removes all particlespawners for the given position regardless of range
if porticlespawners[minetest.pos_to_string(pos)] then
for k,v in pairs(porticlespawners[minetest.pos_to_string(pos)]) do
local p=minetest.get_player_by_name(k)
local dst=PORTICLE_DISTANCE+1 --if player is logged off remove the particlespawner
if p and p:is_player() then
dst=vector.distance(p:get_pos(),pos)
end
if dst > PORTICLE_DISTANCE or force then
remove_particlespawner_at_position(k,pos)
end
end
end
end
local function check_porticlespawners(pos,node)
add_porticlespawners(pos,node)
remove_porticlespawners(pos)
end
-- Destroy portal if pos (portal frame or portal node) got destroyed
local function destroy_nether_portal(pos)
local meta = minetest.get_meta(pos)
@ -77,6 +139,7 @@ local function destroy_nether_portal(pos)
local node = minetest.get_node(pos)
if node and (node.name == "mcl_portals:portal" and (orientation == nil or (node.param2 == orientation))) then
minetest.log("action", "[mcl_portal] Destroying Nether portal at " .. minetest.pos_to_string(pos))
remove_porticlespawners(pos,true)
return minetest.remove_node(pos)
end
end
@ -769,56 +832,16 @@ local function teleport(obj, portal_pos)
end
end
minetest.register_abm({
label = "Nether portal teleportation and particles",
nodenames = {"mcl_portals:portal"},
interval = 1,
chance = 1,
action = function(pos, node)
local o = node.param2 -- orientation
local d = math.random(0, 1) -- direction
local time = math.random() * 1.9 + 0.5
local velocity, acceleration
if o == 1 then
velocity = {x = math.random() * 0.7 + 0.3, y = math.random() - 0.5, z = math.random() - 0.5}
acceleration = {x = math.random() * 1.1 + 0.3, y = math.random() - 0.5, z = math.random() - 0.5}
else
velocity = {x = math.random() - 0.5, y = math.random() - 0.5, z = math.random() * 0.7 + 0.3}
acceleration = {x = math.random() - 0.5, y = math.random() - 0.5, z = math.random() * 1.1 + 0.3}
end
local distance = vector.add(vector.multiply(velocity, time), vector.multiply(acceleration, time * time / 2))
if d == 1 then
if o == 1 then
distance.x = -distance.x
velocity.x = -velocity.x
acceleration.x = -acceleration.x
else
distance.z = -distance.z
velocity.z = -velocity.z
acceleration.z = -acceleration.z
end
end
distance = vector.subtract(pos, distance)
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 15)) do
if obj:is_player() then
minetest.add_particlespawner({
amount = node_particles_allowed_level + 1,
minpos = distance,
maxpos = distance,
minvel = velocity,
maxvel = velocity,
minacc = acceleration,
maxacc = acceleration,
minexptime = time,
maxexptime = time,
minsize = 0.3,
maxsize = 1.8,
collisiondetection = false,
texture = "mcl_particles_nether_portal.png",
playername = obj:get_player_name(),
})
end
end
check_porticlespawners(pos)
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do --maikerumine added for objects to travel
local lua_entity = obj:get_luaentity() --maikerumine added for objects to travel
if (obj:is_player() or lua_entity) and prevent_portal_chatter(obj) then