mirror of
https://git.minetest.land/MineClone2/MineClone2.git
synced 2025-01-10 18:47:31 +01:00
spawn room check that tolerates plants
This commit is contained in:
parent
2f457d9c32
commit
4be9503794
@ -153,7 +153,7 @@ function mcl_mobs.register_mob(name, def)
|
|||||||
attack_type = def.attack_type,
|
attack_type = def.attack_type,
|
||||||
attack_frequency = def.attack_frequency,
|
attack_frequency = def.attack_frequency,
|
||||||
fly = def.fly or false,
|
fly = def.fly or false,
|
||||||
fly_in = def.fly_in or {"air", "__airlike"},
|
fly_in = (type(def.fly_in) == "string" and {def.fly_in}) or def.fly_in or {"air"},
|
||||||
owner = def.owner or "",
|
owner = def.owner or "",
|
||||||
order = def.order or "",
|
order = def.order or "",
|
||||||
on_die = def.on_die,
|
on_die = def.on_die,
|
||||||
|
@ -297,19 +297,13 @@ function mob_class:flight_check()
|
|||||||
|
|
||||||
if not def then return false end -- nil check
|
if not def then return false end -- nil check
|
||||||
|
|
||||||
local fly_in
|
for _,checknode in pairs(self.fly_in or {"air"}) do
|
||||||
if type(self.fly_in) == "string" then
|
|
||||||
fly_in = { self.fly_in }
|
|
||||||
elseif type(self.fly_in) == "table" then
|
|
||||||
fly_in = self.fly_in
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
for _,checknode in pairs(fly_in) do
|
|
||||||
if nod == checknode or nod == "ignore" then
|
if nod == checknode or nod == "ignore" then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
if checknode == "air" and def.drawtype == "airlike" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -532,16 +532,14 @@ end
|
|||||||
|
|
||||||
local function has_room(self, pos)
|
local function has_room(self, pos)
|
||||||
local cb = self.spawnbox or self.collisionbox
|
local cb = self.spawnbox or self.collisionbox
|
||||||
local nodes = {}
|
local nodes = self.fly_in or { "air" }
|
||||||
if self.fly_in then
|
local airlike = false
|
||||||
local t = type(self.fly_in)
|
for i=1,#nodes do
|
||||||
if t == "table" then
|
if nodes[i] == "air" then
|
||||||
nodes = table.copy(self.fly_in)
|
airlike = true
|
||||||
elseif t == "string" then
|
break
|
||||||
table.insert(nodes,self.fly_in)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.insert(nodes,"air")
|
|
||||||
|
|
||||||
-- Calculate area to check for room
|
-- Calculate area to check for room
|
||||||
local cb_height = cb[5] - cb[2]
|
local cb_height = cb[5] - cb[2]
|
||||||
@ -555,61 +553,41 @@ local function has_room(self, pos)
|
|||||||
math.round(pos.z + cb[6]))
|
math.round(pos.z + cb[6]))
|
||||||
|
|
||||||
-- Check if the entire spawn volume is free
|
-- Check if the entire spawn volume is free
|
||||||
local dx = p2.x - p1.x + 1
|
local p = vector.copy(p1)
|
||||||
local dy = p2.y - p1.y + 1
|
local headroom = cb_height - (p2.y - p1.y) -- headroom needed in top layer
|
||||||
local dz = p2.z - p1.z + 1
|
for y = p1.y,p2.y do
|
||||||
local found_nodes = minetest.find_nodes_in_area(p1,p2,nodes) or 0
|
p.y = y
|
||||||
local n = #found_nodes
|
local check_headroom = headroom < 1 and y == p2.y and minetest.get_node_boxes
|
||||||
if n == dx * dy * dz then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 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
|
for z = p1.z,p2.z do
|
||||||
local test_pos = vector.new(x,p2.y,z)
|
p.z = z
|
||||||
local node = minetest.get_node(test_pos) or { name = "ignore" }
|
for x = p1.x,p2.x do
|
||||||
local cache_name = string.format("%s-%d", node.name, node.param2)
|
p.x = x
|
||||||
if not processed[cache_name] then
|
local node = get_node(p)
|
||||||
-- Calculate node bounding box and select the lowest y value
|
local nam = node.name
|
||||||
local boxes = minetest.get_node_boxes("collision_box", test_pos, node)
|
if nam == "ignore" then goto continue end
|
||||||
|
if nam == "air" and airlike then goto continue end
|
||||||
|
if airlike then
|
||||||
|
local n_def = registered_nodes[nam]
|
||||||
|
if not n_def then goto continue end
|
||||||
|
if not n_def.walkable and n_def.liquidtype == "none" then goto continue end
|
||||||
|
end
|
||||||
|
for i = 1,#nodes do
|
||||||
|
-- todo: support groups, too?
|
||||||
|
if nam == nodes[i] then goto continue end
|
||||||
|
end
|
||||||
|
if not check_headroom then return false end
|
||||||
|
-- perform sub-node checks in top layer
|
||||||
|
local boxes = minetest.get_node_boxes("collision_box", p, node)
|
||||||
for i = 1,#boxes do
|
for i = 1,#boxes do
|
||||||
local box = boxes[i]
|
local box = boxes[i]
|
||||||
local y_test = box[2] + 0.5
|
if box[2] + 0.5 < headroom then return false end
|
||||||
if y_test < top_layer_height then top_layer_height = y_test end
|
if box[5] + 0.5 < headroom then return false end
|
||||||
|
|
||||||
local y_test = box[5] + 0.5
|
|
||||||
if y_test < top_layer_height then top_layer_height = y_test end
|
|
||||||
end
|
end
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if top_layer_height + dy - 1 >= cb_height then return true end
|
return true
|
||||||
|
|
||||||
-- We don't have room
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_mobs.custom_biomecheck = nil
|
mcl_mobs.custom_biomecheck = nil
|
||||||
@ -701,6 +679,9 @@ function mcl_mobs.spawn(pos,id)
|
|||||||
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
|
if not has_room(def, pos) then return false end
|
||||||
|
if math.round(pos.y) == pos.y then -- node spawn
|
||||||
|
pos.y = pos.y - 0.5 - def.collisionbox[2] -- spawn just above ground below
|
||||||
|
end
|
||||||
local obj = minetest.add_entity(pos, def.name)
|
local obj = minetest.add_entity(pos, def.name)
|
||||||
-- initialize head bone
|
-- initialize head bone
|
||||||
if def.head_swivel and def.head_bone_position then
|
if def.head_swivel and def.head_bone_position then
|
||||||
|
Loading…
Reference in New Issue
Block a user