123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- local c_lava_source = minetest.get_content_id("default:lava_source")
- local c_lava_flowing = minetest.get_content_id("default:lava_flowing")
- local portal_disconnected_animation_tile = {
- name = "underworld_portal_disconnected_side.png",
- backface_culling = false,
- animation = {
- type = "vertical_frames",
- aspect_w = 16,
- aspect_h = 16,
- length = 0.5,
- }
- }
- local portal_vm_data = {}
- minetest.register_node("underworld:portal_disconnected", {
- description = "Underworld Portal (Disconnected)",
- drawtype = "nodebox",
- node_box = {
- type = "fixed",
- fixed = {
- {-0.499, -0.499, -0.499, 0.499, 0.499, 0.499}, -- Not 0.5, 0.5, ... due to visual glitches
- },
- },
- tiles = {
- "underworld_transparent.png",
- {name = "underworld_portal_disconnected_bottom.png", backface_culling = false},
- portal_disconnected_animation_tile,
- portal_disconnected_animation_tile,
- portal_disconnected_animation_tile,
- portal_disconnected_animation_tile,
- },
- paramtype = "light",
- sunlight_propagates = true,
- walkable = false,
- diggable = false,
- pointable = false,
- buildable_to = false,
- is_ground_content = false,
- drop = "",
- light_source = math.floor(minetest.LIGHT_MAX / 2),
- groups = {attached_node = 1, not_in_creative_inventory = 1},
-
- on_construct = function(pos)
- minetest.get_node_timer(pos):start(0)
- end,
-
- on_timer = function(pos)
- local meta = minetest.get_meta(pos)
- local target_pos = minetest.string_to_pos(meta:get_string("target"))
- if not target_pos then
- local min_search_y, max_search_y
- if pos.y > underworld.depth then
- min_search_y = -31000
- max_search_y = underworld.depth - underworld.barrier_size
- else
- min_search_y = -50
- max_search_y = 200
- end
-
- local search_pos = {x = pos.x + math.random(-40, 40), y = math.random(min_search_y, max_search_y), z = pos.z + math.random(-40, 40)}
- local minp = vector.subtract(search_pos, 40)
- local maxp = vector.add(search_pos, 40)
-
- minetest.emerge_area(
- minp,
- maxp,
- function(_, _, calls_remaining)
- if calls_remaining == 0 then
- local target_dist
- local vm = minetest.get_voxel_manip()
- local emin, emax = vm:read_from_map(minp, maxp)
- local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
- vm:get_data(portal_vm_data)
-
- for z = math.max(minp.z, emin.z), math.min(maxp.z, emax.z) do
- for y = math.max(min_search_y, minp.y, emin.y), math.min(max_search_y, maxp.y, emax.y) do
- for x = math.max(minp.x, emin.x), math.min(maxp.x, emax.x) do
- local cid = portal_vm_data[area:index(x, y, z)]
- if cid == minetest.CONTENT_AIR then
- -- Check if node belown is walkable and node above is air
- local under_cid = portal_vm_data[area:index(x, y - 1, z)]
- local under_node_name = minetest.get_name_from_content_id(under_cid)
- local above_cid = portal_vm_data[area:index(x, y + 1, z)]
- if minetest.registered_nodes[under_node_name].walkable and above_cid == minetest.CONTENT_AIR then
- -- Check for surrounding lava
- local lava_around = false
- for check_z = -5, 5 do
- for check_y = -5, 5 do
- for check_x = -5, 5 do
- local check_cid = portal_vm_data[area:index(x + check_x, y + check_y, z + check_z)]
- if check_cid == c_lava_source or check_cid == c_lava_flowing then
- lava_around = true
- end
- end
- end
- end
- if not lava_around then
- -- Found suitable spot
- local found_pos = {x = x, y = y, z = z}
- local found_dist = vector.distance(pos, search_pos)
- if not target_pos or found_dist < target_dist then
- target_pos = found_pos
- target_dist = found_dist
- end
- end
- end
- end
- end
- end
- end
-
- if target_pos then
- if minetest.get_node(pos).name == "underworld:portal_disconnected" then
- minetest.set_node(pos, {name = "underworld:portal"})
- meta:set_string("target", minetest.pos_to_string(target_pos))
- end
- else
- minetest.get_node_timer(pos):start(1) -- Retry search in one second
- end
- end
- end
- )
- end
- end,
- })
- local portal_animation_tile = {
- name = "underworld_portal_side.png",
- backface_culling = false,
- animation = {
- type = "vertical_frames",
- aspect_w = 16,
- aspect_h = 16,
- length = 0.5,
- }
- }
- minetest.register_node("underworld:portal", {
- description = "Underworld Portal",
- drawtype = "nodebox",
- node_box = {
- type = "fixed",
- fixed = {
- {-0.499, -0.499, -0.499, 0.499, 0.499, 0.499}, -- Not 0.5, 0.5, ... due to visual glitches
- },
- },
- tiles = {
- "underworld_transparent.png",
- {name = "underworld_portal_bottom.png", backface_culling = false},
- portal_animation_tile,
- portal_animation_tile,
- portal_animation_tile,
- portal_animation_tile,
- },
- paramtype = "light",
- sunlight_propagates = true,
- walkable = false,
- diggable = false,
- pointable = false,
- buildable_to = false,
- is_ground_content = false,
- drop = "",
- light_source = math.floor(minetest.LIGHT_MAX / 2),
- groups = {attached_node = 1, not_in_creative_inventory = 1},
- })
- local function teleport_ps_def(pos)
- return {
- texture = "underworld_portal_particle.png",
-
- amount = 500,
- time = 0.5,
-
- minpos = vector.subtract(pos, 0.5),
- maxpos = vector.add(pos, 0.5),
- minvel = {x = -2, y = -2, z = -2},
- maxvel = {x = 2, y = 2, z = 2},
- minacc = {x = 0, y = 0, z = 0},
- maxacc = {x = 0, y = 0, z = 0},
- minexptime = 1,
- maxexptime = 1,
- minsize = 0.5,
- maxsize = 2,
-
- glow = minetest.LIGHT_MAX,
- }
- end
- minetest.register_abm({
- label = "Manage portals",
- nodenames = {"underworld:portal", "underworld:portal_disconnected"},
- interval = 1,
- chance = 1,
- action = function(pos, node)
- local texture
- if node.name == "underworld:portal" then
- texture = "underworld_portal_particle.png"
- else
- texture = "underworld_portal_disconnected_particle.png"
- end
- minetest.add_particlespawner({
- texture = texture,
-
- amount = 50,
- time = 2,
-
- minpos = vector.subtract(pos, 0.5),
- maxpos = vector.add(pos, 0.5),
- minvel = {x = 0, y = 0.25, z = 0},
- maxvel = {x = 0, y = 0.75, z = 0},
- minacc = {x = 0, y = 0.25, z = 0},
- maxacc = {x = 0, y = 0.75, z = 0},
- minexptime = 0.5,
- maxexptime = 1,
- minsize = 0.5,
- maxsize = 2,
- minexptime = 0.5,
- maxexptime = 1,
- minsize = 0.5,
- maxsize = 2,
-
- glow = math.floor(minetest.LIGHT_MAX / 2),
- })
-
- if node.name == "underworld:portal" and math.random(1, 4) == 1 then
- local target_pos = minetest.string_to_pos(minetest.get_meta(pos):get_string("target"))
- if target_pos then
- for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
- if obj:is_player() then
- -- Force emerge
- minetest.get_voxel_manip():read_from_map(vector.subtract(target_pos, 5), vector.add(target_pos, 5))
- minetest.add_particlespawner(teleport_ps_def(vector.add(obj:get_pos(), {x = 0, y = 1, z = 0})))
- obj:set_pos(target_pos)
- minetest.add_particlespawner(teleport_ps_def(vector.add(obj:get_pos(), {x = 0, y = 1, z = 0})))
- end
- end
- end
- end
- end,
- })
- minetest.register_node("underworld:portal_base", {
- description = "Underworld Portal Base",
- tiles = {
- "default_coal_block.png",
- "default_obsidian.png",
- "default_obsidian.png^(underworld_portal_base_side.png)",
- "default_obsidian.png^(underworld_portal_base_side.png)",
- "default_obsidian.png^(underworld_portal_base_side.png^[transformFY)",
- "default_obsidian.png^(underworld_portal_base_side.png^[transformFY)",
- },
- is_ground_content = false,
- groups = {cracky = 3, level = 2},
- sounds = default.node_sound_stone_defaults(),
-
- on_construct = function(pos)
- local above = vector.add(pos, {x = 0, y = 1, z = 0})
- if minetest.get_node(above).name == "air" then
- minetest.set_node(above, {name = "underworld:portal_disconnected"})
- end
- end,
-
- on_destruct = function(pos)
- local above = vector.add(pos, {x = 0, y = 1, z = 0})
- local above_node_name = minetest.get_node(above).name
- if above_node_name == "underworld:portal_disconnected" or above_node_name == "underworld:portal" then
- minetest.remove_node(above)
- end
- end,
-
- on_rotate = false,
- })
- minetest.register_craft({
- output = "underworld:portal_base",
- recipe = {
- {"default:coalblock", "default:coalblock", "default:coalblock"},
- {"default:mese", "default:mese", "default:mese"},
- {"default:obsidian", "default:obsidian", "default:obsidian"},
- },
- })
|