--[[ Adds environmental spawners to the map. When enabled, the spawners will be added to newly generated Dungeons (Uruk Hai) and Temples (Spider). They are dropping a real mob spawner by change (very small chance). Copyright (C) 2016 - 2023 SaKeL This library is free software; you can redistribute it and/or modify it pos the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to juraj.vajda@gmail.com --]] -- main tables spawners_env = { ENABLED_MODS = {}, MOBS_PROPS = {} } spawners_env.mob_tables = {} function spawners_env.register_spawners() -- check if mods exists and build tables for k, mob_mod in ipairs(spawners_env.ENABLED_MODS) do local modpath = minetest.get_modpath(mob_mod) -- list of mobs and their info if (modpath) then for j, mob in ipairs(spawners_env.MOBS_PROPS[mob_mod]) do -- local mob_egg = nil -- create only environmental spawners if mob.env then table.insert(spawners_env.mob_tables, { name = mob.name, mod_prefix = mob_mod, egg_name_custom = mob.egg_name_custom, dummy_size = mob.dummy_size, dummy_offset = mob.dummy_offset, dummy_mesh = mob.dummy_mesh, dummy_texture = mob.dummy_texture, night_only = mob.night_only, sound_custom = mob.sound_custom, env = mob.env, boss = mob.boss }) -- use custom egg or create a default egg -- if mob.egg_name_custom ~= '' then -- mob_egg = mob.egg_name_custom -- else -- mob_egg = mob_mod .. ':' .. mob.name -- end end end end end end -- start spawning mobs function spawners_env.start_spawning(pos, how_many, mob_name, mod_prefix, sound_custom) if not (pos or mob_name) then return end -- remove 'spawners_env:' from the string local _mob_name = string.sub(mob_name, 14) local sound_name -- use custom sounds if sound_custom ~= '' then sound_name = sound_custom else sound_name = mod_prefix .. '_' .. _mob_name end if how_many == nil then how_many = math.random(1, 2) end for i = 1, how_many do pos.y = pos.y + 1 local obj = minetest.add_entity(pos, mod_prefix .. ':' .. _mob_name) if obj then if sound_name then minetest.sound_play(sound_name, { pos = pos, max_hear_distance = 100, gain = 5, }) end end end end function spawners_env.check_around_radius(pos) local player_near = false local radius = 21 for _,obj in ipairs(minetest.get_objects_inside_radius(pos, radius)) do if obj:is_player() then player_near = true end end return player_near end function spawners_env.check_node_status(pos, mob, night_only, boss) local player_near = spawners_env.check_around_radius(pos) if player_near or boss then local random_pos local min_node_light = 10 local tod = minetest.get_timeofday() * 24000 local node_light = minetest.get_node_light(pos) if not node_light then return false end local spawn_positions = {} local right = minetest.get_node({ x = pos.x + 1, y = pos.y, z = pos.z }) local front = minetest.get_node({ x = pos.x, y = pos.y, z = pos.z + 1 }) local left = minetest.get_node({ x = pos.x - 1, y = pos.y, z = pos.z }) local back = minetest.get_node({ x = pos.x, y = pos.y, z = pos.z - 1 }) local top = minetest.get_node({ x = pos.x, y = pos.y + 1, z = pos.z }) local bottom = minetest.get_node({ x = pos.x, y = pos.y - 1, z = pos.z }) -- make sure that at least one side of the spawner is open if right.name == 'air' then table.insert(spawn_positions, { x = pos.x + 1.5, y = pos.y, z = pos.z }) end if front.name == 'air' then table.insert(spawn_positions, { x = pos.x, y = pos.y, z = pos.z + 1.5 }) end if left.name == 'air' then table.insert(spawn_positions, { x = pos.x - 1.5, y = pos.y, z = pos.z }) end if back.name == 'air' then table.insert(spawn_positions, { x = pos.x, y = pos.y, z = pos.z - 1.5 }) end if top.name == 'air' then table.insert(spawn_positions, { x = pos.x, y = pos.y + 1.5, z = pos.z }) end if bottom.name == 'air' then table.insert(spawn_positions, { x = pos.x, y = pos.y - 1.5, z = pos.z }) end -- spawner is closed from all sides if #spawn_positions < 1 then return false else -- find random position in all posible places local possible_spawn_pos = {} local pick_random_key -- get a position value from the picked/random key for k, v in pairs(spawn_positions) do local node_above = minetest.get_node({ x = v.x, y = v.y + 1, z = v.z }).name local node_below = minetest.get_node({ x = v.x, y = v.y - 1, z = v.z }).name -- make super sure there is enough place to spawn mob and collect all possible spawn points if node_above == 'air' or node_below == 'air' then table.insert(possible_spawn_pos, v) -- print('possible pos: ' .. minetest.pos_to_string(v)) end end -- no possible spawn points found - not enough place around the spawner if #possible_spawn_pos < 1 then return false elseif #possible_spawn_pos == 1 then -- only one possible position ? pick_random_key = #possible_spawn_pos else -- pick random from the possible open sides pick_random_key = math.random(1, #possible_spawn_pos) end random_pos = possible_spawn_pos[pick_random_key] -- print(minetest.pos_to_string(random_pos)) end if night_only ~= 'disable' then -- spawn only at day if not night_only and node_light < min_node_light then return false, true end -- spawn only at night if night_only then if not (19359 > tod and tod > 5200) or node_light < min_node_light then return random_pos else return false, true end end end -- random_pos, waiting return random_pos, false else -- random_pos, waiting return false, true end end