mirror of
https://github.com/ElCeejo/creatura.git
synced 2025-03-21 15:21:24 +00:00
Add Context Based Steering, ABM Spawning fixes
This commit is contained in:
parent
5b4b5e7331
commit
64de7d9ed5
4 changed files with 185 additions and 101 deletions
63
api.lua
63
api.lua
|
@ -121,9 +121,11 @@ function creatura.get_node_height_from_def(name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local get_node = minetest.get_node
|
||||||
|
|
||||||
function creatura.get_node_def(node) -- Node can be name or pos
|
function creatura.get_node_def(node) -- Node can be name or pos
|
||||||
if type(node) == "table" then
|
if type(node) == "table" then
|
||||||
node = minetest.get_node(node).name
|
node = get_node(node).name
|
||||||
end
|
end
|
||||||
local def = minetest.registered_nodes[node] or default_node_def
|
local def = minetest.registered_nodes[node] or default_node_def
|
||||||
if def.walkable
|
if def.walkable
|
||||||
|
@ -133,45 +135,28 @@ function creatura.get_node_def(node) -- Node can be name or pos
|
||||||
return def
|
return def
|
||||||
end
|
end
|
||||||
|
|
||||||
function creatura.get_ground_level(pos, max_diff)
|
local get_node_def = creatura.get_node_def
|
||||||
local pos2 = pos -- Prevent modifying table that shouldn't be changed
|
|
||||||
pos2.y = math.floor(pos2.y - 0.49)
|
function creatura.get_ground_level(pos, range)
|
||||||
local node = minetest.get_node(pos2)
|
range = range or 2
|
||||||
local node_under = minetest.get_node({
|
local above = vector.round(pos)
|
||||||
x = pos2.x,
|
local under = {x = above.x, y = above.y - 1, z = above.z}
|
||||||
y = pos2.y - 1,
|
if not get_node_def(above).walkable and get_node_def(under).walkable then return above end
|
||||||
z = pos2.z
|
if get_node_def(above).walkable then
|
||||||
})
|
for i = 1, range do
|
||||||
local walkable = creatura.get_node_def(node_under.name).walkable and not creatura.get_node_def(node.name).walkable
|
under = above
|
||||||
if walkable then
|
above = {x = above.x, y = above.y + 1, z = above.z}
|
||||||
return pos2
|
if not get_node_def(above).walkable and get_node_def(under).walkable then return above end
|
||||||
end
|
|
||||||
if not creatura.get_node_def(node_under.name).walkable then
|
|
||||||
for _ = 1, max_diff do
|
|
||||||
pos2.y = pos2.y - 1
|
|
||||||
node = minetest.get_node(pos2)
|
|
||||||
node_under = minetest.get_node({
|
|
||||||
x = pos2.x,
|
|
||||||
y = pos2.y - 1,
|
|
||||||
z = pos2.z
|
|
||||||
})
|
|
||||||
walkable = creatura.get_node_def(node_under.name).walkable and not creatura.get_node_def(node.name).walkable
|
|
||||||
if walkable then break end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for _ = 1, max_diff do
|
|
||||||
pos2.y = pos2.y + 1
|
|
||||||
node = minetest.get_node(pos2)
|
|
||||||
node_under = minetest.get_node({
|
|
||||||
x = pos2.x,
|
|
||||||
y = pos2.y - 1,
|
|
||||||
z = pos2.z
|
|
||||||
})
|
|
||||||
walkable = creatura.get_node_def(node_under.name).walkable and not creatura.get_node_def(node.name).walkable
|
|
||||||
if walkable then break end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return pos2
|
if not get_node_def(under).walkable then
|
||||||
|
for i = 1, range do
|
||||||
|
above = under
|
||||||
|
under = {x = under.x, y = under.y - 1, z = under.z}
|
||||||
|
if not get_node_def(above).walkable and get_node_def(under).walkable then return above end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return above
|
||||||
end
|
end
|
||||||
|
|
||||||
function creatura.is_pos_moveable(pos, width, height)
|
function creatura.is_pos_moveable(pos, width, height)
|
||||||
|
@ -192,7 +177,7 @@ function creatura.is_pos_moveable(pos, width, height)
|
||||||
local ray = minetest.raycast(pos3, pos4, false, false)
|
local ray = minetest.raycast(pos3, pos4, false, false)
|
||||||
for pointed_thing in ray do
|
for pointed_thing in ray do
|
||||||
if pointed_thing.type == "node" then
|
if pointed_thing.type == "node" then
|
||||||
local name = minetest.get_node(pointed_thing.under).name
|
local name = get_node(pointed_thing.under).name
|
||||||
if creatura.get_node_def(name).walkable then
|
if creatura.get_node_def(name).walkable then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
168
methods.lua
168
methods.lua
|
@ -14,25 +14,27 @@ local function diff(a, b) -- Get difference between 2 angles
|
||||||
return atan2(sin(b - a), cos(b - a))
|
return atan2(sin(b - a), cos(b - a))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function clamp(val, min, max)
|
local function clamp(val, _min, _max)
|
||||||
if val < min then
|
if val < _min then
|
||||||
val = min
|
val = _min
|
||||||
elseif max < val then
|
elseif _max < val then
|
||||||
val = max
|
val = _max
|
||||||
end
|
end
|
||||||
return val
|
return val
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local vec_add = vector.add
|
||||||
local vec_normal = vector.normalize
|
local vec_normal = vector.normalize
|
||||||
local vec_len = vector.length
|
local vec_len = vector.length
|
||||||
local vec_dist = vector.distance
|
local vec_dist = vector.distance
|
||||||
local vec_dir = vector.direction
|
local vec_dir = vector.direction
|
||||||
|
local vec_dot = vector.dot
|
||||||
local vec_multi = vector.multiply
|
local vec_multi = vector.multiply
|
||||||
local vec_add = vector.add
|
local vec_sub = vector.subtract
|
||||||
local yaw2dir = minetest.yaw_to_dir
|
local yaw2dir = minetest.yaw_to_dir
|
||||||
local dir2yaw = minetest.dir_to_yaw
|
local dir2yaw = minetest.dir_to_yaw
|
||||||
|
|
||||||
--[[local function debugpart(pos, time, tex)
|
local function debugpart(pos, time, tex)
|
||||||
minetest.add_particle({
|
minetest.add_particle({
|
||||||
pos = pos,
|
pos = pos,
|
||||||
texture = tex or "creatura_particle_red.png",
|
texture = tex or "creatura_particle_red.png",
|
||||||
|
@ -40,7 +42,7 @@ local dir2yaw = minetest.dir_to_yaw
|
||||||
glow = 16,
|
glow = 16,
|
||||||
size = 16
|
size = 16
|
||||||
})
|
})
|
||||||
end]]
|
end
|
||||||
|
|
||||||
---------------------
|
---------------------
|
||||||
-- Local Utilities --
|
-- Local Utilities --
|
||||||
|
@ -101,35 +103,50 @@ end]]
|
||||||
return false
|
return false
|
||||||
end]]
|
end]]
|
||||||
|
|
||||||
function creatura.get_collision_ranged(self, range)
|
local get_node_def = creatura.get_node_def
|
||||||
local yaw = self.object:get_yaw()
|
local get_node_height = creatura.get_node_height_from_def
|
||||||
local pos = self.object:get_pos()
|
|
||||||
|
function creatura.get_collision_ranged(self, dir, range)
|
||||||
|
local pos, yaw = self.object:get_pos(), self.object:get_yaw()
|
||||||
if not pos then return end
|
if not pos then return end
|
||||||
local width = self.width
|
local width = self.width + 0.1
|
||||||
local height = self.height
|
local height = self.height + self.stepheight
|
||||||
pos.y = pos.y + 0.01
|
pos.y = pos.y + 0.01
|
||||||
local m_dir = vec_normal(yaw2dir(yaw))
|
dir = vec_normal(dir or yaw2dir(yaw))
|
||||||
m_dir.x, m_dir.z = m_dir.x * 0.5, m_dir.z * 0.5
|
yaw = dir2yaw(dir)
|
||||||
local ahead = vec_add(pos, vec_multi(m_dir, width + 0.5))
|
local ahead = vec_add(pos, vec_multi(dir, width))
|
||||||
-- Loop
|
-- Loop
|
||||||
|
local cos_yaw = cos(yaw)
|
||||||
|
local sin_yaw = sin(yaw)
|
||||||
local pos_x, pos_y, pos_z = ahead.x, ahead.y, ahead.z
|
local pos_x, pos_y, pos_z = ahead.x, ahead.y, ahead.z
|
||||||
|
local dir_x, dir_y, dir_z = dir.x, dir.y, dir.z
|
||||||
|
local dist
|
||||||
|
local collision
|
||||||
for i = 0, range or 4 do
|
for i = 0, range or 4 do
|
||||||
pos_x = pos_x + m_dir.x * i
|
pos_x = pos_x + dir_x
|
||||||
pos_y = pos_y + m_dir.y * i
|
pos_y = pos_y + dir_y
|
||||||
pos_z = pos_z + m_dir.z * i
|
pos_z = pos_z + dir_z
|
||||||
|
local pos2
|
||||||
for x = -width, width, width / ceil(width) do
|
for x = -width, width, width / ceil(width) do
|
||||||
|
pos2 = {
|
||||||
|
x = cos_yaw * ((pos_x + x) - pos_x) + pos_x,
|
||||||
|
y = pos_y,
|
||||||
|
z = sin_yaw * ((pos_x + x) - pos_x) + pos_z
|
||||||
|
}
|
||||||
for y = 0, height, height / ceil(height) do
|
for y = 0, height, height / ceil(height) do
|
||||||
local pos2 = {
|
pos2.y = pos_y + y
|
||||||
x = cos(yaw) * ((pos_x + x) - pos_x) + pos_x,
|
local dist2 = vec_dist(pos, pos2)
|
||||||
y = pos.y + y,
|
if not dist
|
||||||
z = sin(yaw) * ((pos_x + x) - pos_x) + pos_z
|
or dist2 < dist then
|
||||||
}
|
if pos2.y - pos_y > (self.stepheight or 1.1)
|
||||||
if pos2.y - pos.y > (self.stepheight or 1.1)
|
and get_node_def(pos2).walkable then
|
||||||
and creatura.get_node_def(pos2).walkable then
|
collision = pos2
|
||||||
return true, pos2
|
dist = dist2
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if collision then return true, collision end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
@ -144,16 +161,19 @@ function creatura.get_collision(self)
|
||||||
local m_dir = vec_normal(yaw2dir(yaw))
|
local m_dir = vec_normal(yaw2dir(yaw))
|
||||||
local ahead = vec_add(pos, vec_multi(m_dir, width + 1)) -- 1 node out from edge of box
|
local ahead = vec_add(pos, vec_multi(m_dir, width + 1)) -- 1 node out from edge of box
|
||||||
-- Loop
|
-- Loop
|
||||||
|
local cos_yaw = cos(yaw)
|
||||||
|
local sin_yaw = sin(yaw)
|
||||||
local pos_x, pos_z = ahead.x, ahead.z
|
local pos_x, pos_z = ahead.x, ahead.z
|
||||||
for x = -width, width, width / ceil(width) do
|
for x = -width, width, width / ceil(width) do
|
||||||
|
local pos2 = {
|
||||||
|
x = cos_yaw * ((pos_x + x) - pos_x) + pos_x,
|
||||||
|
y = pos.y,
|
||||||
|
z = sin_yaw * ((pos_x + x) - pos_x) + pos_z
|
||||||
|
}
|
||||||
for y = 0, height, height / ceil(height) do
|
for y = 0, height, height / ceil(height) do
|
||||||
local pos2 = {
|
pos2.y = pos.y + y
|
||||||
x = cos(yaw) * ((pos_x + x) - pos_x) + pos_x,
|
|
||||||
y = pos.y + y,
|
|
||||||
z = sin(yaw) * ((pos_x + x) - pos_x) + pos_z
|
|
||||||
}
|
|
||||||
if pos2.y - pos.y > (self.stepheight or 1.1)
|
if pos2.y - pos.y > (self.stepheight or 1.1)
|
||||||
and creatura.get_node_def(pos2).walkable then
|
and get_node_def(pos2).walkable then
|
||||||
return true, pos2
|
return true, pos2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -179,6 +199,65 @@ local function get_avoidance_dir(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local steer_directions = {
|
||||||
|
vec_normal({x = 1, y = 0, z = 0}),
|
||||||
|
vec_normal({x = 1, y = 0, z = 1}),
|
||||||
|
vec_normal({x = 0, y = 0, z = 1}),
|
||||||
|
vec_normal({x = -1, y = 0, z = 0}),
|
||||||
|
vec_normal({x = -1, y = 0, z = -1}),
|
||||||
|
vec_normal({x = 0, y = 0, z = -1}),
|
||||||
|
vec_normal({x = 1, y = 0, z = -1}),
|
||||||
|
vec_normal({x = -1, y = 0, z = 1})
|
||||||
|
}
|
||||||
|
|
||||||
|
function creatura.get_context_steering(self, goal, range)
|
||||||
|
local pos, vel = self.object:get_pos(), self.object:get_velocity()
|
||||||
|
if not pos then return end
|
||||||
|
local heading = vec_normal(vel)
|
||||||
|
local dir2goal = vec_normal(vec_dir(pos, goal))
|
||||||
|
local output_dir = {x = 0, y = dir2goal.y, z = 0}
|
||||||
|
range = range or 8
|
||||||
|
if range < 2 then range = 2 end
|
||||||
|
for _, _dir in ipairs(steer_directions) do
|
||||||
|
local dir = table.copy(_dir)
|
||||||
|
local score = vec_dot(dir2goal, dir)
|
||||||
|
local interest = clamp(score, 0, 1)
|
||||||
|
local danger = 0
|
||||||
|
if interest >= 0 then
|
||||||
|
local width = self.width
|
||||||
|
local height = self.height
|
||||||
|
local collision
|
||||||
|
if width <= 0.5
|
||||||
|
and height <= 1 then
|
||||||
|
local pos2 = vec_add(pos, dir)
|
||||||
|
local pos2_name = minetest.get_node(pos2).name
|
||||||
|
collision = get_node_height(pos2_name) > self.stepheight and pos2
|
||||||
|
if not collision then
|
||||||
|
local above = {x = pos2.x, y = pos2.y + 1, z = pos2.z}
|
||||||
|
collision = get_node_def(above).walkable and pos2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local s_range = range * clamp(interest, 0.5, 1)
|
||||||
|
_, collision = creatura.get_collision_ranged(self, dir, s_range)
|
||||||
|
end
|
||||||
|
if collision then
|
||||||
|
local dir2col = vec_dir(pos, collision)
|
||||||
|
local dist2col = vec_dist(pos, collision) - self.width
|
||||||
|
local ahead = vec_add(pos, vec_multi(heading, self.width + dist2col))
|
||||||
|
local avd_force = vec_normal(vec_sub(ahead, collision))
|
||||||
|
dir.y = avd_force.y / 4
|
||||||
|
local dot_weight = vec_dot(vec_normal(dir2col), dir)
|
||||||
|
local dist_weight = (range - dist2col) / range
|
||||||
|
interest = interest - dot_weight
|
||||||
|
danger = dist_weight
|
||||||
|
end
|
||||||
|
end
|
||||||
|
score = clamp(interest - danger, 0, 1)
|
||||||
|
output_dir = vector.add(output_dir, vector.multiply(dir, score))
|
||||||
|
end
|
||||||
|
return output_dir
|
||||||
|
end
|
||||||
|
|
||||||
-------------
|
-------------
|
||||||
-- Actions --
|
-- Actions --
|
||||||
-------------
|
-------------
|
||||||
|
@ -414,4 +493,27 @@ creatura.register_movement_method("creatura:obstacle_avoidance", function(self)
|
||||||
_self:turn_to(goal_yaw, turn_rate)
|
_self:turn_to(goal_yaw, turn_rate)
|
||||||
end
|
end
|
||||||
return func
|
return func
|
||||||
|
end)
|
||||||
|
|
||||||
|
creatura.register_movement_method("creatura:context_based_steering", function(self)
|
||||||
|
local steer_to
|
||||||
|
local steer_timer = 0.25
|
||||||
|
self:set_gravity(-9.8)
|
||||||
|
local function func(_self, goal, speed_factor)
|
||||||
|
local pos = _self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
|
if vec_dist(pos, goal) < clamp(self.width, 0.5, 1) then
|
||||||
|
_self:halt()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
-- Calculate Movement
|
||||||
|
steer_timer = (steer_timer > 0 and steer_timer - self.dtime) or 0.25
|
||||||
|
steer_to = (steer_timer <= 0 and creatura.get_context_steering(self, goal, 2)) or steer_to
|
||||||
|
local speed = abs(_self.speed or 2) * speed_factor or 0.5
|
||||||
|
local turn_rate = abs(_self.turn_rate or 5)
|
||||||
|
-- Apply Movement
|
||||||
|
_self:set_forward_velocity(speed)
|
||||||
|
_self:turn_to(dir2yaw(steer_to or vec_dir(pos, goal)), turn_rate)
|
||||||
|
end
|
||||||
|
return func
|
||||||
end)
|
end)
|
14
mob_meta.lua
14
mob_meta.lua
|
@ -438,7 +438,7 @@ function mob:is_pos_safe(pos)
|
||||||
for i = 1, self.max_fall or 3 do
|
for i = 1, self.max_fall or 3 do
|
||||||
local fall_pos = {
|
local fall_pos = {
|
||||||
x = pos.x,
|
x = pos.x,
|
||||||
y = floor(mob_pos.y + 0.5) - i,
|
y = floor(pos.y + 0.5) - i,
|
||||||
z = pos.z
|
z = pos.z
|
||||||
}
|
}
|
||||||
if creatura.get_node_def(fall_pos).walkable then
|
if creatura.get_node_def(fall_pos).walkable then
|
||||||
|
@ -695,6 +695,8 @@ end
|
||||||
|
|
||||||
function mob:clear_action()
|
function mob:clear_action()
|
||||||
self._action = {}
|
self._action = {}
|
||||||
|
self._movement_data.goal = nil
|
||||||
|
self._movement_data.func = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function mob:set_utility(func)
|
function mob:set_utility(func)
|
||||||
|
@ -1142,12 +1144,13 @@ function mob:_execute_utilities()
|
||||||
and is_alive then
|
and is_alive then
|
||||||
for i = 1, #self.utility_stack do
|
for i = 1, #self.utility_stack do
|
||||||
local utility = self.utility_stack[i].utility
|
local utility = self.utility_stack[i].utility
|
||||||
|
local util_data = self._utility_data
|
||||||
local get_score = self.utility_stack[i].get_score
|
local get_score = self.utility_stack[i].get_score
|
||||||
local step_delay = self.utility_stack[i].step_delay
|
local step_delay = self.utility_stack[i].step_delay
|
||||||
local score, args = get_score(self)
|
local score, args = get_score(self)
|
||||||
if self._utility_data.utility
|
if util_data.utility
|
||||||
and utility == self._utility_data.utility
|
and utility == util_data.utility
|
||||||
and self._utility_data.score > 0
|
and util_data.score > 0
|
||||||
and score <= 0 then
|
and score <= 0 then
|
||||||
self._utility_data = {
|
self._utility_data = {
|
||||||
utility = nil,
|
utility = nil,
|
||||||
|
@ -1155,9 +1158,10 @@ function mob:_execute_utilities()
|
||||||
step_delay = nil,
|
step_delay = nil,
|
||||||
score = 0
|
score = 0
|
||||||
}
|
}
|
||||||
|
util_data = self._utility_data
|
||||||
end
|
end
|
||||||
if score > 0
|
if score > 0
|
||||||
and score >= self._utility_data.score
|
and score >= util_data.score
|
||||||
and score >= loop_data.score then
|
and score >= loop_data.score then
|
||||||
loop_data = {
|
loop_data = {
|
||||||
utility = utility,
|
utility = utility,
|
||||||
|
|
41
spawning.lua
41
spawning.lua
|
@ -493,23 +493,16 @@ function creatura.register_abm_spawn(mob, def)
|
||||||
|
|
||||||
local function spawn_func(pos, _, _, aocw)
|
local function spawn_func(pos, _, _, aocw)
|
||||||
|
|
||||||
if spawn_on_load
|
|
||||||
and random(chance) > 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if spawn_on_load
|
|
||||||
and not minetest.find_node_near(pos, 1, neighbors) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if pos.y > max_height
|
|
||||||
or pos.y < min_height then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if not spawn_in_nodes then
|
if not spawn_in_nodes then
|
||||||
pos = vec_raise(pos, 1)
|
pos.y = pos.y + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if spawn_on_load -- Manual checks for LBMs
|
||||||
|
and (random(chance) > 1
|
||||||
|
or not minetest.find_node_near(pos, 1, neighbors)
|
||||||
|
or pos.y > max_height
|
||||||
|
or pos.y < min_height) then
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local light = minetest.get_node_light(pos) or 7
|
local light = minetest.get_node_light(pos) or 7
|
||||||
|
@ -530,9 +523,7 @@ function creatura.register_abm_spawn(mob, def)
|
||||||
local objects = minetest.get_objects_inside_radius(pos, abr)
|
local objects = minetest.get_objects_inside_radius(pos, abr)
|
||||||
|
|
||||||
for _, object in ipairs(objects) do
|
for _, object in ipairs(objects) do
|
||||||
local ent = object and object:get_luaentity()
|
local ent = object:get_luaentity()
|
||||||
local is_plyr = object and object:is_player()
|
|
||||||
plyr_found = plyr_found or is_plyr
|
|
||||||
if ent
|
if ent
|
||||||
and ent.name == mob then
|
and ent.name == mob then
|
||||||
mob_count = mob_count + 1
|
mob_count = mob_count + 1
|
||||||
|
@ -540,6 +531,7 @@ function creatura.register_abm_spawn(mob, def)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
plyr_found = plyr_found or object:is_player()
|
||||||
end
|
end
|
||||||
|
|
||||||
if not plyr_found then
|
if not plyr_found then
|
||||||
|
@ -550,8 +542,6 @@ function creatura.register_abm_spawn(mob, def)
|
||||||
local mob_width = mob_def.collisionbox[4]
|
local mob_width = mob_def.collisionbox[4]
|
||||||
local mob_height = math.max(0, mob_def.collisionbox[5] - mob_def.collisionbox[2])
|
local mob_height = math.max(0, mob_def.collisionbox[5] - mob_def.collisionbox[2])
|
||||||
|
|
||||||
pos.y = pos.y - 0.49
|
|
||||||
|
|
||||||
if not creatura.is_pos_moveable(pos, mob_width, mob_height) then
|
if not creatura.is_pos_moveable(pos, mob_width, mob_height) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -560,10 +550,11 @@ function creatura.register_abm_spawn(mob, def)
|
||||||
|
|
||||||
if group_size > 1 then
|
if group_size > 1 then
|
||||||
for _ = 1, group_size do
|
for _ = 1, group_size do
|
||||||
|
local offset = math.ceil(mob_width)
|
||||||
local spawn_pos = creatura.get_ground_level({
|
local spawn_pos = creatura.get_ground_level({
|
||||||
x = pos.x + random(-mob_width, mob_width),
|
x = pos.x + random(-offset, offset),
|
||||||
y = pos.y,
|
y = pos.y,
|
||||||
z = pos.x + random(-mob_width, mob_width),
|
z = pos.x + random(-offset, offset),
|
||||||
}, 3)
|
}, 3)
|
||||||
if not creatura.is_pos_moveable(spawn_pos, mob_width, mob_height) then
|
if not creatura.is_pos_moveable(spawn_pos, mob_width, mob_height) then
|
||||||
spawn_pos = pos
|
spawn_pos = pos
|
||||||
|
@ -589,11 +580,11 @@ function creatura.register_abm_spawn(mob, def)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
minetest.log("action",
|
minetest.log("action",
|
||||||
"[Creatura] [ABM Spawning] Spawned " .. group_size .. " " .. mob .. " at " .. minetest.pos_to_string(pos))
|
"[Creatura] [ABM Spawning] Spawned " .. group_size .. " " .. mob .. " at " .. minetest.pos_to_string(pos))
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if spawn_on_load then
|
if spawn_on_load then
|
||||||
|
@ -613,6 +604,8 @@ function creatura.register_abm_spawn(mob, def)
|
||||||
neighbors = neighbors,
|
neighbors = neighbors,
|
||||||
interval = interval,
|
interval = interval,
|
||||||
chance = chance,
|
chance = chance,
|
||||||
|
min_y = min_height,
|
||||||
|
max_y = max_height,
|
||||||
catch_up = false,
|
catch_up = false,
|
||||||
action = function(pos, ...)
|
action = function(pos, ...)
|
||||||
spawn_func(pos, ...)
|
spawn_func(pos, ...)
|
||||||
|
|
Loading…
Add table
Reference in a new issue