mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2024-11-11 02:31:05 +01:00
Merge pull request 'Correct space check when spawning mobs' (#4445) from fix-has_room into master
Reviewed-on: https://git.minetest.land/VoxeLibre/VoxeLibre/pulls/4445 Reviewed-by: kno10 <kno10@noreply.git.minetest.land>
This commit is contained in:
commit
b239549774
10 changed files with 145 additions and 78 deletions
|
@ -48,6 +48,20 @@ function table.pairs_by_keys(t, f)
|
||||||
return iter
|
return iter
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Removes one element randomly selected from the array section of the table and
|
||||||
|
-- returns it, or nil if there are no elements in the array section of the table
|
||||||
|
function table.remove_random_element(table)
|
||||||
|
local count = #table
|
||||||
|
if count == 0 then return nil end
|
||||||
|
|
||||||
|
local idx = math.random(count)
|
||||||
|
local res = table[idx]
|
||||||
|
table[idx] = table[count]
|
||||||
|
table[count] = nil
|
||||||
|
count = count - 1
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default", false)
|
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_default", false)
|
||||||
local LOG_MODULE = "[MCL2]"
|
local LOG_MODULE = "[MCL2]"
|
||||||
function mcl_util.mcl_log(message, module, bypass_default_logger)
|
function mcl_util.mcl_log(message, module, bypass_default_logger)
|
||||||
|
|
|
@ -105,7 +105,7 @@ end
|
||||||
|
|
||||||
-- Spawn a child
|
-- Spawn a child
|
||||||
function mcl_mobs.spawn_child(pos, mob_type)
|
function mcl_mobs.spawn_child(pos, mob_type)
|
||||||
local child = minetest.add_entity(pos, mob_type)
|
local child = mcl_mobs.spawn(pos, mob_type)
|
||||||
if not child then
|
if not child then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -285,6 +285,7 @@ function mob_class:check_breeding()
|
||||||
end
|
end
|
||||||
|
|
||||||
local child = mcl_mobs.spawn_child(pos, parent1.name)
|
local child = mcl_mobs.spawn_child(pos, parent1.name)
|
||||||
|
if not child then return end
|
||||||
|
|
||||||
local ent_c = child:get_luaentity()
|
local ent_c = child:get_luaentity()
|
||||||
|
|
||||||
|
|
|
@ -528,7 +528,7 @@ end
|
||||||
-- Note: This also introduces the “spawn_egg” group:
|
-- Note: This also introduces the “spawn_egg” group:
|
||||||
-- * spawn_egg=1: Spawn egg (generic mob, no metadata)
|
-- * spawn_egg=1: Spawn egg (generic mob, no metadata)
|
||||||
-- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata)
|
-- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata)
|
||||||
function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addegg, no_creative)
|
function mcl_mobs.register_egg(mob_id, desc, background_color, overlay_color, addegg, no_creative)
|
||||||
|
|
||||||
local grp = {spawn_egg = 1}
|
local grp = {spawn_egg = 1}
|
||||||
|
|
||||||
|
@ -539,7 +539,7 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
||||||
|
|
||||||
local invimg = "(spawn_egg.png^[multiply:" .. background_color ..")^(spawn_egg_overlay.png^[multiply:" .. overlay_color .. ")"
|
local invimg = "(spawn_egg.png^[multiply:" .. background_color ..")^(spawn_egg_overlay.png^[multiply:" .. overlay_color .. ")"
|
||||||
if old_spawn_icons then
|
if old_spawn_icons then
|
||||||
local mobname = mob:gsub("mobs_mc:","")
|
local mobname = mob_id:gsub("mobs_mc:","")
|
||||||
local fn = "mobs_mc_spawn_icon_"..mobname..".png"
|
local fn = "mobs_mc_spawn_icon_"..mobname..".png"
|
||||||
if mcl_util.file_exists(minetest.get_modpath("mobs_mc").."/textures/"..fn) then
|
if mcl_util.file_exists(minetest.get_modpath("mobs_mc").."/textures/"..fn) then
|
||||||
invimg = fn
|
invimg = fn
|
||||||
|
@ -551,7 +551,7 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
||||||
end
|
end
|
||||||
|
|
||||||
-- register old stackable mob egg
|
-- register old stackable mob egg
|
||||||
minetest.register_craftitem(mob, {
|
minetest.register_craftitem(mob_id, {
|
||||||
|
|
||||||
description = desc,
|
description = desc,
|
||||||
inventory_image = invimg,
|
inventory_image = invimg,
|
||||||
|
@ -561,7 +561,6 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
||||||
_doc_items_usagehelp = S("Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns."),
|
_doc_items_usagehelp = S("Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns."),
|
||||||
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
|
||||||
local pos = pointed_thing.above
|
local pos = pointed_thing.above
|
||||||
|
|
||||||
-- am I clicking on something with existing on_rightclick function?
|
-- am I clicking on something with existing on_rightclick function?
|
||||||
|
@ -571,11 +570,12 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
||||||
return def.on_rightclick(pointed_thing.under, under, placer, itemstack)
|
return def.on_rightclick(pointed_thing.under, under, placer, itemstack)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local mob_name = itemstack:get_name()
|
||||||
|
|
||||||
if pos and within_limits(pos, 0) and not minetest.is_protected(pos, placer:get_player_name()) then
|
if pos and within_limits(pos, 0) and not minetest.is_protected(pos, placer:get_player_name()) then
|
||||||
local name = placer:get_player_name()
|
local name = placer:get_player_name()
|
||||||
local privs = minetest.get_player_privs(name)
|
local privs = minetest.get_player_privs(name)
|
||||||
|
|
||||||
|
|
||||||
if under.name == "mcl_mobspawners:spawner" then
|
if under.name == "mcl_mobspawners:spawner" then
|
||||||
if minetest.is_protected(pointed_thing.under, name) then
|
if minetest.is_protected(pointed_thing.under, name) then
|
||||||
minetest.record_protection_violation(pointed_thing.under, name)
|
minetest.record_protection_violation(pointed_thing.under, name)
|
||||||
|
@ -593,7 +593,6 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
||||||
--minetest.log("max light: " .. mob_light_lvl[2])
|
--minetest.log("max light: " .. mob_light_lvl[2])
|
||||||
|
|
||||||
-- Handle egg conversion
|
-- Handle egg conversion
|
||||||
local mob_name = itemstack:get_name()
|
|
||||||
local convert_to = (minetest.registered_entities[mob_name] or {})._convert_to
|
local convert_to = (minetest.registered_entities[mob_name] or {})._convert_to
|
||||||
if convert_to then mob_name = convert_to end
|
if convert_to then mob_name = convert_to end
|
||||||
|
|
||||||
|
@ -604,19 +603,24 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
|
||||||
if not minetest.registered_entities[mob] then
|
if not minetest.registered_entities[mob_name] then
|
||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
|
||||||
if minetest.settings:get_bool("only_peaceful_mobs", false)
|
if minetest.settings:get_bool("only_peaceful_mobs", false)
|
||||||
and minetest.registered_entities[mob].type == "monster" then
|
and minetest.registered_entities[mob_name].type == "monster" then
|
||||||
minetest.chat_send_player(name, S("Only peaceful mobs allowed!"))
|
minetest.chat_send_player(name, S("Only peaceful mobs allowed!"))
|
||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
|
||||||
pos.y = pos.y - 0.5
|
pos.y = pos.y - 1
|
||||||
|
local mob = mcl_mobs.spawn(pos, mob_name)
|
||||||
|
if not object then
|
||||||
|
pos.y = pos.y + 1
|
||||||
|
mob = mcl_mobs.spawn(pos, mob_name)
|
||||||
|
if not mob then return end
|
||||||
|
end
|
||||||
|
|
||||||
local mob = minetest.add_entity(pos, mob)
|
|
||||||
local entityname = itemstack:get_name()
|
local entityname = itemstack:get_name()
|
||||||
minetest.log("action", "Player " ..name.." spawned "..entityname.." at "..minetest.pos_to_string(pos))
|
minetest.log("action", "Player " ..name.." spawned "..entityname.." at "..minetest.pos_to_string(pos))
|
||||||
local ent = mob:get_luaentity()
|
local ent = mob:get_luaentity()
|
||||||
|
@ -647,5 +651,4 @@ function mcl_mobs.register_egg(mob, desc, background_color, overlay_color, addeg
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -530,8 +530,8 @@ local function get_water_spawn(p)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function has_room(self,pos)
|
local function has_room(self, pos)
|
||||||
local cb = self.collisionbox
|
local cb = self.spawnbox or self.collisionbox
|
||||||
local nodes = {}
|
local nodes = {}
|
||||||
if self.fly_in then
|
if self.fly_in then
|
||||||
local t = type(self.fly_in)
|
local t = type(self.fly_in)
|
||||||
|
@ -542,18 +542,74 @@ local function has_room(self,pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.insert(nodes,"air")
|
table.insert(nodes,"air")
|
||||||
local x = cb[4] - cb[1]
|
|
||||||
local y = cb[5] - cb[2]
|
-- Calculate area to check for room
|
||||||
local z = cb[6] - cb[3]
|
local cb_height = cb[5] - cb[2]
|
||||||
local r = math.ceil(x * y * z)
|
local p1 = vector.new(
|
||||||
local p1 = vector.offset(pos,cb[1],cb[2],cb[3])
|
math.round(pos.x + cb[1]),
|
||||||
local p2 = vector.offset(pos,cb[4],cb[5],cb[6])
|
math.floor(pos.y),
|
||||||
local n = #minetest.find_nodes_in_area(p1,p2,nodes) or 0
|
math.round(pos.z + cb[3]))
|
||||||
if r > n then
|
local p2 = vector.new(
|
||||||
minetest.log("warning","[mcl_mobs] No room for mob "..self.name.." at "..minetest.pos_to_string(vector.round(pos)))
|
math.round(pos.x + cb[4]),
|
||||||
return false
|
math.ceil(p1.y + cb_height) - 1,
|
||||||
|
math.round(pos.z + cb[6]))
|
||||||
|
|
||||||
|
-- Check if the entire spawn volume is free
|
||||||
|
local dx = p2.x - p1.x + 1
|
||||||
|
local dy = p2.y - p1.y + 1
|
||||||
|
local dz = p2.z - p1.z + 1
|
||||||
|
local found_nodes = minetest.find_nodes_in_area(p1,p2,nodes) or 0
|
||||||
|
local n = #found_nodes
|
||||||
|
if n == dx * dy * dz then
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
return true
|
|
||||||
|
-- If we don't have an implementation of get_node_boxes, we can't check for sub-node space
|
||||||
|
if not minetest.get_node_boxes then return false end
|
||||||
|
|
||||||
|
-- Check if it's possible for a sub-node space check to succeed
|
||||||
|
local needed_in_bottom_section = dx * ( dy - 1) * dz
|
||||||
|
if n < needed_in_bottom_section then return false end
|
||||||
|
|
||||||
|
-- Make sure the entire volume except for the top level is free before checking the top layer
|
||||||
|
if dy > 1 then
|
||||||
|
-- Remove nodes in the top layer from the count
|
||||||
|
for i = 1,#found_nodes do
|
||||||
|
if found_nodes[i].y == p2.y then
|
||||||
|
n = n - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If the entire volume except the top layer isn't air (or nodes) then we can't spawn this mob here
|
||||||
|
if n < needed_in_bottom_section then return false end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check the top layer to see if we have enough space to spawn in
|
||||||
|
local top_layer_height = 1
|
||||||
|
local processed = {}
|
||||||
|
for x = p1.x,p2.x do
|
||||||
|
for z = p1.z,p2.z do
|
||||||
|
local test_pos = vector.new(x,p2.y,z)
|
||||||
|
local node = minetest.get_node(test_pos) or { name = "ignore" }
|
||||||
|
local cache_name = string.format("%s-%d", node.name, node.param2)
|
||||||
|
if not processed[cache_name] then
|
||||||
|
-- Calculate node bounding box and select the lowest y value
|
||||||
|
local boxes = minetest.get_node_boxes("collision_box", test_pos, node)
|
||||||
|
for i = 1,#boxes do
|
||||||
|
local box = boxes[i]
|
||||||
|
local y_test = box[2] + 0.5
|
||||||
|
if y_test < top_layer_height then top_layer_height = y_test end
|
||||||
|
|
||||||
|
local y_test = box[5] + 0.5
|
||||||
|
if y_test < top_layer_height then top_layer_height = y_test end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if top_layer_height + dy - 1 >= cb_height then return true end
|
||||||
|
|
||||||
|
-- We don't have room
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_mobs.custom_biomecheck = nil
|
mcl_mobs.custom_biomecheck = nil
|
||||||
|
@ -644,10 +700,10 @@ function mcl_mobs.spawn(pos,id)
|
||||||
if not pos or not id then return false end
|
if not pos or not id then return false end
|
||||||
local def = minetest.registered_entities[id] or minetest.registered_entities["mobs_mc:"..id] or minetest.registered_entities["extra_mobs:"..id]
|
local def = minetest.registered_entities[id] or minetest.registered_entities["mobs_mc:"..id] or minetest.registered_entities["extra_mobs:"..id]
|
||||||
if not def or not def.is_mob or (def.can_spawn and not def.can_spawn(pos)) then return false end
|
if not def or not def.is_mob or (def.can_spawn and not def.can_spawn(pos)) then return false end
|
||||||
|
if not has_room(def, pos) then return false end
|
||||||
return minetest.add_entity(pos, def.name)
|
return minetest.add_entity(pos, def.name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function spawn_group(p,mob,spawn_on,amount_to_spawn)
|
local function spawn_group(p,mob,spawn_on,amount_to_spawn)
|
||||||
local nn= minetest.find_nodes_in_area_under_air(vector.offset(p,-5,-3,-5),vector.offset(p,5,3,5),spawn_on)
|
local nn= minetest.find_nodes_in_area_under_air(vector.offset(p,-5,-3,-5),vector.offset(p,5,3,5),spawn_on)
|
||||||
local o
|
local o
|
||||||
|
|
|
@ -53,12 +53,14 @@ local spawn_children_on_die = function(child_mob, spawn_distance, eject_speed)
|
||||||
eject_speed = eject_speed * 0.5
|
eject_speed = eject_speed * 0.5
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local mob = minetest.add_entity(newpos, child_mob)
|
local mob = mcl_mobs.spawn(newpos, child_mob)
|
||||||
if not mother_stuck then
|
if mob then
|
||||||
mob:set_velocity(dir * eject_speed)
|
if not mother_stuck then
|
||||||
|
mob:set_velocity(dir * eject_speed)
|
||||||
|
end
|
||||||
|
mob:set_yaw(angle - math.pi/2)
|
||||||
|
table.insert(children, mob)
|
||||||
end
|
end
|
||||||
mob:set_yaw(angle - math.pi/2)
|
|
||||||
table.insert(children, mob)
|
|
||||||
angle = angle + (math.pi*2) / spawn_count
|
angle = angle + (math.pi*2) / spawn_count
|
||||||
end
|
end
|
||||||
-- If mother was murdered, children attack the killer after 1 second
|
-- If mother was murdered, children attack the killer after 1 second
|
||||||
|
|
|
@ -67,6 +67,7 @@ local spider = {
|
||||||
curiosity = 10,
|
curiosity = 10,
|
||||||
head_yaw="z",
|
head_yaw="z",
|
||||||
collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.89, 0.7},
|
collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.89, 0.7},
|
||||||
|
spawnbox = {-1.2, -0.01, -1.2, 1.2, 0.89, 1.2},
|
||||||
visual = "mesh",
|
visual = "mesh",
|
||||||
mesh = "mobs_mc_spider.b3d",
|
mesh = "mobs_mc_spider.b3d",
|
||||||
textures = {
|
textures = {
|
||||||
|
|
|
@ -1049,14 +1049,18 @@ local function has_summon_participants(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function summon_golem(self)
|
local function summon_golem(self)
|
||||||
vector.offset(self.object:get_pos(),-10,-10,-10)
|
local pos = self.object:get_pos()
|
||||||
local nn = minetest.find_nodes_in_area_under_air(vector.offset(self.object:get_pos(),-10,-10,-10),vector.offset(self.object:get_pos(),10,10,10),{"group:solid","group:water"})
|
local p1 = vector.offset(pos, -10, -10, -10)
|
||||||
table.shuffle(nn)
|
local p2 = vector.offset(pos, 10, 10, 10)
|
||||||
for _,n in pairs(nn) do
|
local nn = minetest.find_nodes_in_area_under_air(p1, p2,{"group:solid","group:water"})
|
||||||
local up = minetest.find_nodes_in_area(vector.offset(n,0,1,0),vector.offset(n,0,3,0),{"air"})
|
while #nn > 0 do
|
||||||
if up and #up >= 3 then
|
local n = table.remove_random_element(nn)
|
||||||
|
n.y = n.y + 1
|
||||||
|
|
||||||
|
local summon = mcl_mobs.spawn(n, "mobs_mc:iron_golem")
|
||||||
|
if summon then
|
||||||
minetest.sound_play("mcl_portals_open_end_portal", {pos=n, gain=0.5, max_hear_distance = 16}, true)
|
minetest.sound_play("mcl_portals_open_end_portal", {pos=n, gain=0.5, max_hear_distance = 16}, true)
|
||||||
return minetest.add_entity(vector.offset(n,0,1,0),"mobs_mc:iron_golem")
|
return summon
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -55,14 +55,16 @@ mcl_mobs.register_mob("mobs_mc:evoker", {
|
||||||
basepos.y = basepos.y + 1
|
basepos.y = basepos.y + 1
|
||||||
for i=1, r do
|
for i=1, r do
|
||||||
local spawnpos = vector.add(basepos, minetest.yaw_to_dir(pr:next(0,360)))
|
local spawnpos = vector.add(basepos, minetest.yaw_to_dir(pr:next(0,360)))
|
||||||
local vex = minetest.add_entity(spawnpos, "mobs_mc:vex")
|
local vex = mcl_mobs.spawn(spawnpos, "mobs_mc:vex")
|
||||||
local ent = vex:get_luaentity()
|
if vex then
|
||||||
|
local ent = vex:get_luaentity()
|
||||||
|
|
||||||
-- Mark vexes as summoned and start their life clock (they take damage it reaches 0)
|
-- Mark vexes as summoned and start their life clock (they take damage it reaches 0)
|
||||||
ent._summoned = true
|
ent._summoned = true
|
||||||
ent._lifetimer = pr:next(33, 108)
|
ent._lifetimer = pr:next(33, 108)
|
||||||
|
|
||||||
table.insert(spawned_vexes[self],ent)
|
table.insert(spawned_vexes[self],ent)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
passive = false,
|
passive = false,
|
||||||
|
|
|
@ -19,7 +19,6 @@ local set_node = minetest.set_node
|
||||||
local sound_play = minetest.sound_play
|
local sound_play = minetest.sound_play
|
||||||
local add_particlespawner = minetest.add_particlespawner
|
local add_particlespawner = minetest.add_particlespawner
|
||||||
local after = minetest.after
|
local after = minetest.after
|
||||||
local add_entity = minetest.add_entity
|
|
||||||
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
||||||
local get_item_group = minetest.get_item_group
|
local get_item_group = minetest.get_item_group
|
||||||
|
|
||||||
|
@ -165,7 +164,7 @@ function lightning.strike_func(pos, pos2, objects)
|
||||||
|
|
||||||
-- Events caused by the lightning strike: Fire, damage, mob transformations, rare skeleton spawn
|
-- Events caused by the lightning strike: Fire, damage, mob transformations, rare skeleton spawn
|
||||||
|
|
||||||
pos2.y = pos2.y + 1/2
|
pos2.y = pos2.y + 1
|
||||||
local skeleton_lightning = false
|
local skeleton_lightning = false
|
||||||
if rng:next(1,100) <= 3 then
|
if rng:next(1,100) <= 3 then
|
||||||
skeleton_lightning = true
|
skeleton_lightning = true
|
||||||
|
@ -174,14 +173,14 @@ function lightning.strike_func(pos, pos2, objects)
|
||||||
if get_node(pos2).name == "air" then
|
if get_node(pos2).name == "air" then
|
||||||
-- Low chance for a lightning to spawn skeleton horse + skeletons
|
-- Low chance for a lightning to spawn skeleton horse + skeletons
|
||||||
if skeleton_lightning then
|
if skeleton_lightning then
|
||||||
add_entity(pos2, "mobs_mc:skeleton_horse")
|
mcl_mobs.spawn(pos2, "mobs_mc:skeleton_horse")
|
||||||
|
|
||||||
local angle, posadd
|
local angle, posadd
|
||||||
angle = math.random() * math.pi * 2
|
angle = math.random() * math.pi * 2
|
||||||
for i=1,3 do
|
for i=1,3 do
|
||||||
posadd = { x=math.cos(angle),y=0,z=math.sin(angle) }
|
posadd = { x=math.cos(angle),y=0,z=math.sin(angle) }
|
||||||
posadd = vector.normalize(posadd)
|
posadd = vector.normalize(posadd)
|
||||||
local mob = add_entity(vector.add(pos2, posadd), "mobs_mc:skeleton")
|
local mob = mcl_mobs.spawn(vector.add(pos2, posadd), "mobs_mc:skeleton")
|
||||||
if mob then
|
if mob then
|
||||||
mob:set_yaw(angle-math.pi/2)
|
mob:set_yaw(angle-math.pi/2)
|
||||||
end
|
end
|
||||||
|
|
|
@ -147,20 +147,14 @@ local function spawn_mobs(pos, elapsed)
|
||||||
-- get meta
|
-- get meta
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
|
|
||||||
-- get settings
|
|
||||||
local mob = meta:get_string("Mob")
|
|
||||||
local mlig = meta:get_int("MinLight")
|
|
||||||
local xlig = meta:get_int("MaxLight")
|
|
||||||
local num = meta:get_int("MaxMobsInArea")
|
|
||||||
local pla = meta:get_int("PlayerDistance")
|
|
||||||
local yof = meta:get_int("YOffset")
|
|
||||||
|
|
||||||
-- if amount is 0 then do nothing
|
-- if amount is 0 then do nothing
|
||||||
|
local num = meta:get_int("MaxMobsInArea")
|
||||||
if num == 0 then
|
if num == 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- are we spawning a registered mob?
|
-- are we spawning a registered mob?
|
||||||
|
local mob = meta:get_string("Mob")
|
||||||
if not mcl_mobs.spawning_mobs[mob] then
|
if not mcl_mobs.spawning_mobs[mob] then
|
||||||
minetest.log("error", "[mcl_mobspawners] Mob Spawner: Mob doesn't exist: "..mob)
|
minetest.log("error", "[mcl_mobspawners] Mob Spawner: Mob doesn't exist: "..mob)
|
||||||
return
|
return
|
||||||
|
@ -174,17 +168,14 @@ local function spawn_mobs(pos, elapsed)
|
||||||
local timer = minetest.get_node_timer(pos)
|
local timer = minetest.get_node_timer(pos)
|
||||||
|
|
||||||
-- spawn mob if player detected and in range
|
-- spawn mob if player detected and in range
|
||||||
|
local pla = meta:get_int("PlayerDistance")
|
||||||
if pla > 0 then
|
if pla > 0 then
|
||||||
|
|
||||||
local in_range = 0
|
local in_range = 0
|
||||||
local objs = minetest.get_objects_inside_radius(pos, pla)
|
local objs = minetest.get_objects_inside_radius(pos, pla)
|
||||||
|
|
||||||
for _,oir in pairs(objs) do
|
for _,oir in pairs(objs) do
|
||||||
|
|
||||||
if oir:is_player() then
|
if oir:is_player() then
|
||||||
|
|
||||||
in_range = 1
|
in_range = 1
|
||||||
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -213,7 +204,6 @@ local function spawn_mobs(pos, elapsed)
|
||||||
|
|
||||||
-- count mob objects of same type in area
|
-- count mob objects of same type in area
|
||||||
for k, obj in ipairs(objs) do
|
for k, obj in ipairs(objs) do
|
||||||
|
|
||||||
ent = obj:get_luaentity()
|
ent = obj:get_luaentity()
|
||||||
|
|
||||||
if ent and ent.name and ent.name == mob then
|
if ent and ent.name and ent.name == mob then
|
||||||
|
@ -228,33 +218,28 @@ local function spawn_mobs(pos, elapsed)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- find air blocks within 8×3×8 nodes of spawner
|
-- find air blocks within 8×3×8 nodes of spawner
|
||||||
|
local yof = meta:get_int("YOffset")
|
||||||
local air = minetest.find_nodes_in_area(
|
local air = minetest.find_nodes_in_area(
|
||||||
{x = pos.x - 4, y = pos.y - 1 + yof, z = pos.z - 4},
|
{x = pos.x - 4, y = pos.y - 1 + yof, z = pos.z - 4},
|
||||||
{x = pos.x + 4, y = pos.y + 1 + yof, z = pos.z + 4},
|
{x = pos.x + 4, y = pos.y + 1 + yof, z = pos.z + 4},
|
||||||
{"air"})
|
{"air"})
|
||||||
|
|
||||||
-- spawn up to 4 mobs in random air blocks
|
-- spawn mobs in random air blocks. Default max of 4
|
||||||
if air then
|
if air then
|
||||||
local max = 4
|
local num_to_spawn = spawn_count_overrides[mob] or 4
|
||||||
if spawn_count_overrides[mob] then
|
local mlig = meta:get_int("MinLight")
|
||||||
max = spawn_count_overrides[mob]
|
local xlig = meta:get_int("MaxLight")
|
||||||
end
|
|
||||||
for a=1, max do
|
|
||||||
if #air <= 0 then
|
|
||||||
-- We're out of space! Stop spawning
|
|
||||||
break
|
|
||||||
end
|
|
||||||
local air_index = math.random(#air)
|
|
||||||
local pos2 = air[air_index]
|
|
||||||
local lig = minetest.get_node_light(pos2) or 0
|
|
||||||
|
|
||||||
pos2.y = pos2.y + 0.5
|
|
||||||
|
|
||||||
|
while #air > 0 do
|
||||||
|
local pos2 = table.remove_random_element(air)
|
||||||
-- only if light levels are within range
|
-- only if light levels are within range
|
||||||
|
local lig = minetest.get_node_light(pos2) or 0
|
||||||
if lig >= mlig and lig <= xlig then
|
if lig >= mlig and lig <= xlig then
|
||||||
minetest.add_entity(pos2, mob)
|
if mcl_mobs.spawn(pos2, mob) then
|
||||||
|
num_to_spawn = num_to_spawn - 1
|
||||||
|
if num_to_spawn == 0 then break end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
table.remove(air, air_index)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue