Improve free space checks on mob spawn

This commit is contained in:
Wuzzy 2019-02-05 17:05:40 +01:00
parent f63342ec72
commit 64457b151c
1 changed files with 48 additions and 10 deletions

View File

@ -3176,11 +3176,13 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
-- is mob actually registered? -- is mob actually registered?
if not mobs.spawning_mobs[name] if not mobs.spawning_mobs[name]
or not minetest.registered_entities[name] then or not minetest.registered_entities[name] then
minetest.log("warning", "Mob spawn of "..name.." failed, unknown entity or mob is not registered for spawning!")
return return
end end
-- additional custom checks for spawning mob -- additional custom checks for spawning mob
if mobs:spawn_abm_check(pos, node, name) == true then if mobs:spawn_abm_check(pos, node, name) == true then
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, ABM check rejected!")
return return
end end
@ -3188,6 +3190,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
if active_object_count_wider >= max_per_block if active_object_count_wider >= max_per_block
or count_mobs(pos, name) >= aoc then or count_mobs(pos, name) >= aoc then
-- too many entities -- too many entities
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!")
return return
end end
@ -3200,12 +3203,14 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
-- daylight, but mob wants night -- daylight, but mob wants night
if day_toggle == false then if day_toggle == false then
-- mob needs night -- mob needs night
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs light!")
return return
end end
else else
-- night time but mob wants day -- night time but mob wants day
if day_toggle == true then if day_toggle == true then
-- mob needs day -- mob needs day
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs daylight!")
return return
end end
end end
@ -3221,7 +3226,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
if objs[n]:is_player() then if objs[n]:is_player() then
-- player too close -- player too close
minetest.log("info", "Mob spawn of ".. name .. " failed, player too close") minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, player too close!")
return return
end end
end end
@ -3229,12 +3234,14 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
-- mobs cannot spawn in protected areas when enabled -- mobs cannot spawn in protected areas when enabled
if not spawn_protected if not spawn_protected
and minetest.is_protected(pos, "") then and minetest.is_protected(pos, "") then
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, position is protected!")
return return
end end
-- are we spawning within height limits? -- are we spawning within height limits?
if pos.y > max_height if pos.y > max_height
or pos.y < min_height then or pos.y < min_height then
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, out of height limit!")
return return
end end
@ -3243,27 +3250,58 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
if not light if not light
or light > max_light or light > max_light
or light < min_light then or light < min_light then
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, bad light!")
return return
end end
-- do we have enough height clearance to spawn mob? -- do we have enough space to spawn mob?
local ent = minetest.registered_entities[name] local ent = minetest.registered_entities[name]
local height = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1) local width_x = max(1, math.ceil(ent.collisionbox[4] - ent.collisionbox[1]))
local min_x, max_x
if width_x % 2 == 0 then
max_x = math.floor(width_x/2)
min_x = -(max_x-1)
else
max_x = math.floor(width_x/2)
min_x = -max_x
end
for n = 0, height do local width_z = max(1, math.ceil(ent.collisionbox[6] - ent.collisionbox[3]))
local min_z, max_z
if width_z % 2 == 0 then
max_z = math.floor(width_z/2)
min_z = -(max_z-1)
else
max_z = math.floor(width_z/2)
min_z = -max_z
end
local pos2 = {x = pos.x, y = pos.y + n, z = pos.z} local max_y = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1)
for y = 0, max_y do
for x = min_x, max_x do
for z = min_z, max_z do
local pos2 = {x = pos.x+x, y = pos.y+y, z = pos.z+z}
if minetest.registered_nodes[node_ok(pos2).name].walkable == true then if minetest.registered_nodes[node_ok(pos2).name].walkable == true then
-- inside block -- inside block
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!")
return return
end end
end end
end
end
-- spawn mob half block higher than ground -- spawn mob with half of its height above ground
pos.y = pos.y + 0.5 pos.y = pos.y + ((ent.collisionbox[2] - ent.collisionbox[5]) / 2)
if width_x % 2 == 0 then
pos.x = pos.x + 0.5
end
if width_z % 2 == 0 then
pos.z = pos.z + 0.5
end
local mob = minetest.add_entity(pos, name) local mob = minetest.add_entity(pos, name)
minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos))
if on_spawn then if on_spawn then