mirror of
https://github.com/ElCeejo/animalia.git
synced 2025-03-22 23:52:21 +00:00
Update Movement API, Fix potential crashes
This commit is contained in:
parent
93c5127d1c
commit
db1c6c84ca
1 changed files with 1349 additions and 1407 deletions
|
@ -79,40 +79,7 @@ local moveable = creatura.is_pos_moveable
|
||||||
local fast_ray_sight = creatura.fast_ray_sight
|
local fast_ray_sight = creatura.fast_ray_sight
|
||||||
local get_node_def = creatura.get_node_def
|
local get_node_def = creatura.get_node_def
|
||||||
|
|
||||||
local function get_ground_level(pos2, max_height)
|
local get_ground_level = creatura.get_ground_level
|
||||||
local node = minetest.get_node(pos2)
|
|
||||||
local node_under = minetest.get_node({
|
|
||||||
x = pos2.x,
|
|
||||||
y = pos2.y - 1,
|
|
||||||
z = pos2.z
|
|
||||||
})
|
|
||||||
local height = 0
|
|
||||||
local walkable = is_solid[node_under.name] and not is_solid[node.name]
|
|
||||||
if walkable then
|
|
||||||
return pos2
|
|
||||||
elseif not walkable then
|
|
||||||
if not is_solid[node_under.name] then
|
|
||||||
while not is_solid[node_under.name]
|
|
||||||
and height < max_height do
|
|
||||||
pos2.y = pos2.y - 1
|
|
||||||
node_under = minetest.get_node({
|
|
||||||
x = pos2.x,
|
|
||||||
y = pos2.y - 1,
|
|
||||||
z = pos2.z
|
|
||||||
})
|
|
||||||
height = height + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
while is_solid[node.name]
|
|
||||||
and height < max_height do
|
|
||||||
pos2.y = pos2.y + 1
|
|
||||||
node = minetest.get_node(pos2)
|
|
||||||
height = height + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return pos2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_ceiling_positions(pos, range)
|
local function get_ceiling_positions(pos, range)
|
||||||
local walkable = minetest.find_nodes_in_area(
|
local walkable = minetest.find_nodes_in_area(
|
||||||
|
@ -137,41 +104,67 @@ local function get_ceiling_positions(pos, range)
|
||||||
return output
|
return output
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_obstacle_avoidance(self, lift)
|
local function get_collision(self, yaw)
|
||||||
|
local width = self.width
|
||||||
|
local height = self.height
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local yaw = self.object:get_yaw()
|
if not pos then return end
|
||||||
pos.y = pos.y + self.stepheight
|
pos.y = pos.y + 1
|
||||||
local vel = self.object:get_velocity()
|
local pos2 = vec_add(pos, vec_multi(yaw2dir(yaw), width + 5))
|
||||||
local vel_len = abs(vector.length(vel))
|
for x = -width, width, width / ceil(width) do
|
||||||
if vel_len < 1.5 then
|
for y = 0, height, height / ceil(height) do
|
||||||
vel_len = 1.5
|
local vec1 = {
|
||||||
|
x = cos(yaw) * ((pos.x + x) - pos.x) + pos.x,
|
||||||
|
y = pos.y + y,
|
||||||
|
z = sin(yaw) * ((pos.x + x) - pos.x) + pos.z
|
||||||
|
}
|
||||||
|
local vec2 = {
|
||||||
|
x = cos(yaw) * ((pos2.x + x) - pos2.x) + pos2.x,
|
||||||
|
y = vec1.y,
|
||||||
|
z = sin(yaw) * ((pos2.x + x) - pos2.x) + pos2.z
|
||||||
|
}
|
||||||
|
local ray = minetest.raycast(vec1, vec2, false, true)
|
||||||
|
for pointed_thing in ray do
|
||||||
|
if pointed_thing
|
||||||
|
and pointed_thing.type == "node" then
|
||||||
|
return true, pointed_thing.intersection_point
|
||||||
end
|
end
|
||||||
local dir = yaw2dir(yaw)
|
|
||||||
dir.y = lift
|
|
||||||
local outset = vec_add(pos, vec_multi(dir, vel_len))
|
|
||||||
local pos2
|
|
||||||
local obstacle = false
|
|
||||||
if not fast_ray_sight(pos, outset) then
|
|
||||||
pos2 = vec_add(pos, vec_multi(dir, -vel_len))
|
|
||||||
obstacle = true
|
|
||||||
end
|
end
|
||||||
return pos2, obstacle
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_wander_pos_3d(self, range)
|
local function get_obstacle_avoidance(self, goal)
|
||||||
local outset = random(range or 4)
|
local width = self.width
|
||||||
|
local height = self.height
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local move_dir = {
|
if not pos then return end
|
||||||
x = random(-10, 10) * 0.1,
|
pos.y = pos.y + 1
|
||||||
z = random(-10, 10) * 0.1,
|
local yaw2goal = dir2yaw(vec_dir(pos, goal))
|
||||||
y = random(-10, 10) * 0.1
|
local collide, col_pos = get_collision(self, yaw2goal)
|
||||||
}
|
if not collide then return end
|
||||||
local pos2 = vec_add(pos, vec_multi(vec_normal(move_dir), random(1, outset)))
|
local avd_pos
|
||||||
local sight, dist = fast_ray_sight(pos, pos2, true)
|
for i = 45, 180, 45 do
|
||||||
if not sight then
|
local angle = rad(i)
|
||||||
pos2 = vec_add(pos, vec_multi(vec_normal(move_dir), dist - 0.5))
|
local dir = vec_multi(yaw2dir(yaw2goal + angle), width)
|
||||||
|
avd_pos = vec_center(vec_add(pos, dir))
|
||||||
|
if not get_collision(self, yaw2goal) then
|
||||||
|
break
|
||||||
end
|
end
|
||||||
return pos2
|
angle = -rad(i)
|
||||||
|
dir = vec_multi(yaw2dir(yaw2goal + angle), width)
|
||||||
|
avd_pos = vec_center(vec_add(pos, dir))
|
||||||
|
if not get_collision(self, yaw2goal) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if col_pos.y - (pos.y + height * 0.5) > 1 then
|
||||||
|
avd_pos.y = avd_pos.y - 3
|
||||||
|
elseif (pos.y + height * 0.5) - col_pos.y > 1 then
|
||||||
|
avd_pos.y = avd_pos.y + 3
|
||||||
|
end
|
||||||
|
return avd_pos
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_boid_members(pos, radius, name, texture_no)
|
local function get_boid_members(pos, radius, name, texture_no)
|
||||||
|
@ -196,197 +189,133 @@ end
|
||||||
-- Movement Methods --
|
-- Movement Methods --
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
local function movement_fly(self, pos2)
|
-- Flying --
|
||||||
-- Initial Properties
|
|
||||||
|
creatura.register_movement_method("animalia:fly_obstacle_avoidance", function(self, goal)
|
||||||
|
local waypoint
|
||||||
|
local tick = 0.15
|
||||||
|
local box = clamp(self.width, 0.5, ceil(self.width))
|
||||||
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local turn_rate = self.turn_rate or 10
|
if not pos then return end
|
||||||
local speed = self.speed or 2
|
-- Return true when goal is reached
|
||||||
|
if self:pos_in_box(goal, box) then
|
||||||
|
self:halt()
|
||||||
|
return true
|
||||||
|
end
|
||||||
self:animate("fly")
|
self:animate("fly")
|
||||||
self:set_gravity(0)
|
tick = tick - self.dtime
|
||||||
-- Collision Avoidance
|
if tick <= 0 then
|
||||||
local temp_goal = self._movement_data.temp_goal
|
if not waypoint
|
||||||
local obstacle = self._movement_data.obstacle or false
|
or self:pos_in_box(waypoint, box) then
|
||||||
if not temp_goal
|
waypoint = get_obstacle_avoidance(self, goal)
|
||||||
or self:pos_in_box(temp_goal, self.width) then
|
|
||||||
self._movement_data.temp_goal, self._movement_data.obstacle = get_obstacle_avoidance(self, vec_dir(pos, pos2).y)
|
|
||||||
end
|
end
|
||||||
local neighbor = self._movement_data.temp_goal
|
tick = 0.15
|
||||||
-- Calculate Movement
|
|
||||||
local dir = vector.direction(pos, pos2)
|
|
||||||
local tyaw = minetest.dir_to_yaw(dir)
|
|
||||||
if neighbor then
|
|
||||||
local lift = dir.y
|
|
||||||
dir = vector.direction(pos, neighbor)
|
|
||||||
if not obstacle then
|
|
||||||
dir.y = lift
|
|
||||||
end
|
end
|
||||||
tyaw = minetest.dir_to_yaw(dir)
|
-- Get movement direction
|
||||||
|
local goal_dir = vec_dir(pos, goal)
|
||||||
|
if waypoint then
|
||||||
|
goal_dir = vec_dir(pos, waypoint)
|
||||||
end
|
end
|
||||||
if self._path
|
local yaw = self.object:get_yaw()
|
||||||
and #self._path > 1 then
|
local goal_yaw = dir2yaw(goal_dir)
|
||||||
neighbor = self._path[2]
|
if abs(yaw - goal_yaw) > 0.1 then
|
||||||
dir = vector.direction(pos, neighbor)
|
self:turn_to(goal_yaw, self.turn_rate or 6)
|
||||||
tyaw = minetest.dir_to_yaw(dir)
|
|
||||||
if self:pos_in_box(neighbor, self.width + 0.2) then
|
|
||||||
table.remove(self._path, 1)
|
|
||||||
end
|
end
|
||||||
|
-- Set Velocity
|
||||||
|
self:set_forward_velocity(self.speed or 2)
|
||||||
|
self:set_vertical_velocity((self.speed or 2) * goal_dir.y)
|
||||||
|
end
|
||||||
|
return func
|
||||||
|
end)
|
||||||
|
|
||||||
|
creatura.register_movement_method("animalia:fly_pathfind", function(self, goal)
|
||||||
|
local waypoint
|
||||||
|
local tick = 0.15
|
||||||
|
local box = clamp(self.width, 0.5, ceil(self.width))
|
||||||
|
local function func(self)
|
||||||
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
|
-- Return true when goal is reached
|
||||||
|
if self:pos_in_box(goal, box) then
|
||||||
|
self:halt()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
self:animate("fly")
|
||||||
|
tick = tick - self.dtime
|
||||||
|
if tick <= 0 then
|
||||||
|
if not waypoint
|
||||||
|
or self:pos_in_box(waypoint, box) then
|
||||||
|
waypoint = get_obstacle_avoidance(self, goal)
|
||||||
|
end
|
||||||
|
tick = 0.15
|
||||||
|
end
|
||||||
|
-- Get movement direction
|
||||||
|
local goal_dir = vec_dir(pos, goal)
|
||||||
|
if waypoint then
|
||||||
|
-- There's an obstruction, time to find a path
|
||||||
|
if #path < 1 then
|
||||||
|
path = creatura.find_theta_path(self, pos, goal, self.width, self.height, 300, false, true) or {}
|
||||||
else
|
else
|
||||||
self._path = creatura.find_path(self, pos, pos2, self.width, self.height, 300, false, true)
|
waypoint = path[2] or path[1]
|
||||||
end
|
end
|
||||||
-- Apply Movement
|
goal_dir = vec_dir(pos, waypoint)
|
||||||
self:turn_to(tyaw, turn_rate)
|
|
||||||
self:set_forward_velocity(speed)
|
|
||||||
local v_speed = speed * dir.y
|
|
||||||
local vel = self.object:get_velocity()
|
|
||||||
vel.y = vel.y + (v_speed - vel.y) * 0.2
|
|
||||||
self:set_vertical_velocity(vel.y)
|
|
||||||
if self:pos_in_box(pos2) then
|
|
||||||
self:halt()
|
|
||||||
end
|
end
|
||||||
|
local yaw = self.object:get_yaw()
|
||||||
|
local goal_yaw = dir2yaw(goal_dir)
|
||||||
|
if abs(yaw - goal_yaw) > 0.1 then
|
||||||
|
self:turn_to(goal_yaw, self.turn_rate or 6)
|
||||||
end
|
end
|
||||||
|
-- Set Velocity
|
||||||
creatura.register_movement_method("animalia:fly_path", movement_fly)
|
self:set_forward_velocity(self.speed or 2)
|
||||||
|
self:set_vertical_velocity((self.speed or 2) * goal_dir.y)
|
||||||
local function movement_fly_waypoints(self, pos2, speed)
|
|
||||||
-- Initial Properties
|
|
||||||
local pos = self.object:get_pos()
|
|
||||||
self:animate("fly")
|
|
||||||
self:set_gravity(0)
|
|
||||||
-- Collision Avoidance
|
|
||||||
local temp_goal = self._movement_data.temp_goal
|
|
||||||
local obstacle = self._movement_data.obstacle or false
|
|
||||||
if not temp_goal
|
|
||||||
or self:pos_in_box(temp_goal, 0.4) then
|
|
||||||
self._movement_data.temp_goal, self._movement_data.obstacle = get_obstacle_avoidance(self, vec_dir(pos, pos2).y)
|
|
||||||
end
|
end
|
||||||
local neighbor = self._movement_data.temp_goal
|
return func
|
||||||
-- Calculate Movement
|
end)
|
||||||
local dir = vector.direction(pos, pos2)
|
|
||||||
local tyaw = minetest.dir_to_yaw(dir)
|
|
||||||
local turn_rate = self.turn_rate or 10
|
|
||||||
local speed = self.speed or 2
|
|
||||||
if neighbor then
|
|
||||||
local lift = dir.y
|
|
||||||
dir = vector.direction(pos, neighbor)
|
|
||||||
if not obstacle then
|
|
||||||
dir.y = lift
|
|
||||||
end
|
|
||||||
tyaw = minetest.dir_to_yaw(dir)
|
|
||||||
end
|
|
||||||
-- Apply Movement
|
|
||||||
self:turn_to(boid_angle or tyaw, turn_rate)
|
|
||||||
self:set_forward_velocity(speed)
|
|
||||||
local v_speed = speed * dir.y
|
|
||||||
local vel = self.object:get_velocity()
|
|
||||||
vel.y = vel.y + (v_speed - vel.y) * 0.2
|
|
||||||
self:set_vertical_velocity(vel.y)
|
|
||||||
if self:pos_in_box(pos2) then
|
|
||||||
self:halt()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
creatura.register_movement_method("animalia:fly_waypoints", movement_fly_waypoints)
|
|
||||||
|
|
||||||
-- Fly Obstacle Avoidance --
|
|
||||||
|
|
||||||
local function movement_fly_obstacle_avoidance(self, pos2, speed)
|
|
||||||
-- Initial Properties
|
|
||||||
local pos = self.object:get_pos()
|
|
||||||
local turn_rate = self.turn_rate or 10
|
|
||||||
local speed = self.speed or 2
|
|
||||||
self:animate("fly")
|
|
||||||
self:set_gravity(0)
|
|
||||||
-- Collision Avoidance
|
|
||||||
local temp_goal = self._movement_data.temp_goal
|
|
||||||
local obstacle = self._movement_data.obstacle or false
|
|
||||||
local timer = self._movement_data.timer
|
|
||||||
if not temp_goal
|
|
||||||
or self:pos_in_box(temp_goal, 0.4)
|
|
||||||
or (timer
|
|
||||||
and timer <= 0) then
|
|
||||||
self._movement_data.temp_goal, self._movement_data.obstacle = get_obstacle_avoidance(self, vec_dir(pos, pos2).y)
|
|
||||||
temp_goal = self._movement_data.temp_goal
|
|
||||||
obstacle = self._movement_data.obstacle or false
|
|
||||||
if temp_goal then
|
|
||||||
self._movement_data.timer = 3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if timer then
|
|
||||||
self._movement_data.timer = self._movement_data.timer - self.dtime
|
|
||||||
end
|
|
||||||
-- Calculate Movement
|
|
||||||
local dir = vector.direction(pos, pos2)
|
|
||||||
local tyaw = minetest.dir_to_yaw(dir)
|
|
||||||
if temp_goal
|
|
||||||
and obstacle then
|
|
||||||
dir = vector.direction(pos, temp_goal)
|
|
||||||
dir.y = vec_dir(pos, pos2).y
|
|
||||||
tyaw = minetest.dir_to_yaw(dir)
|
|
||||||
end
|
|
||||||
-- Apply Movement
|
|
||||||
self:turn_to(tyaw, turn_rate)
|
|
||||||
self:set_forward_velocity(speed)
|
|
||||||
local v_speed = (speed) * dir.y
|
|
||||||
local vel = self.object:get_velocity()
|
|
||||||
vel.y = vel.y + (v_speed - vel.y) * 0.2
|
|
||||||
self:set_vertical_velocity(vel.y)
|
|
||||||
if self:pos_in_box(pos2, 0.5) then
|
|
||||||
self:halt()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
creatura.register_movement_method("animalia:fly_obstacle_avoidance", movement_fly_obstacle_avoidance)
|
|
||||||
|
|
||||||
-- Swimming --
|
-- Swimming --
|
||||||
|
|
||||||
local function movement_swim_obstacle_avoidance(self, pos2, speed)
|
creatura.register_movement_method("animalia:swim_obstacle_avoidance", function(self, goal)
|
||||||
-- Initial Properties
|
local waypoint
|
||||||
|
local tick = 0.15
|
||||||
|
local box = clamp(self.width, 0.5, ceil(self.width))
|
||||||
|
local function func(self)
|
||||||
|
if self.in_liquid then
|
||||||
|
self:set_gravity(-9.8)
|
||||||
|
return true
|
||||||
|
end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
self:animate("swim")
|
if not pos then return end
|
||||||
self:set_gravity(0)
|
-- Return true when goal is reached
|
||||||
-- Collision Avoidance
|
if vec_dist(pos, goal) < self.width * 1.33 then
|
||||||
local temp_goal = self._movement_data.temp_goal
|
|
||||||
local obstacle = self._movement_data.obstacle or false
|
|
||||||
local timer = self._movement_data.timer
|
|
||||||
if not temp_goal
|
|
||||||
or self:pos_in_box(temp_goal, 0.4)
|
|
||||||
or (timer
|
|
||||||
and timer <= 0) then
|
|
||||||
self._movement_data.temp_goal, self._movement_data.obstacle = get_obstacle_avoidance(self, vec_dir(pos, pos2).y)
|
|
||||||
temp_goal = self._movement_data.temp_goal
|
|
||||||
obstacle = self._movement_data.obstacle or false
|
|
||||||
if temp_goal then
|
|
||||||
self._movement_data.timer = vec_dist(pos, temp_goal) / self.speed
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if timer then
|
|
||||||
self._movement_data.timer = self._movement_data.timer - self.dtime
|
|
||||||
end
|
|
||||||
-- Calculate Movement
|
|
||||||
local dir = vector.direction(pos, pos2)
|
|
||||||
local tyaw = minetest.dir_to_yaw(dir)
|
|
||||||
if temp_goal
|
|
||||||
and obstacle then
|
|
||||||
dir = vector.direction(pos, temp_goal)
|
|
||||||
tyaw = minetest.dir_to_yaw(dir)
|
|
||||||
end
|
|
||||||
-- Apply Movement
|
|
||||||
self:turn_to(tyaw, turn_rate)
|
|
||||||
self:set_forward_velocity(speed)
|
|
||||||
local v_speed = speed * dir.y
|
|
||||||
local vel = self.object:get_velocity()
|
|
||||||
vel.y = vel.y + (v_speed - vel.y) * 0.2
|
|
||||||
if not is_liquid[minetest.get_node(vec_raise(pos, 1)).name]
|
|
||||||
and vel.y > 0 then
|
|
||||||
vel.y = 0
|
|
||||||
end
|
|
||||||
self:set_vertical_velocity(vel.y)
|
|
||||||
if self:pos_in_box(pos2) then
|
|
||||||
self:halt()
|
self:halt()
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
self:animate("swim")
|
||||||
|
tick = tick - self.dtime
|
||||||
|
if tick <= 0 then
|
||||||
|
if not waypoint
|
||||||
|
or vec_dist(pos, waypoint) < self.width * 1.33 then
|
||||||
|
waypoint = get_obstacle_avoidance(self, goal)
|
||||||
end
|
end
|
||||||
|
tick = 0.15
|
||||||
creatura.register_movement_method("animalia:swim_obstacle_avoidance", movement_swim_obstacle_avoidance)
|
end
|
||||||
|
-- Get movement direction
|
||||||
|
local goal_dir = vec_dir(pos, goal)
|
||||||
|
if waypoint then
|
||||||
|
goal_dir = vec_dir(pos, waypoint)
|
||||||
|
end
|
||||||
|
local yaw = self.object:get_yaw()
|
||||||
|
local goal_yaw = dir2yaw(goal_dir)
|
||||||
|
if abs(yaw - goal_yaw) > 0.1 then
|
||||||
|
self:turn_to(goal_yaw, self.turn_rate or 6)
|
||||||
|
end
|
||||||
|
-- Set Velocity
|
||||||
|
self:set_forward_velocity(self.speed or 2)
|
||||||
|
self:set_vertical_velocity((self.speed or 2) * goal_dir.y)
|
||||||
|
end
|
||||||
|
return func
|
||||||
|
end)
|
||||||
|
|
||||||
-------------
|
-------------
|
||||||
-- Actions --
|
-- Actions --
|
||||||
|
@ -473,11 +402,10 @@ function animalia.action_boid_move(self, pos2, timeout, method)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if timer <= 0
|
if timer <= 0
|
||||||
or self:pos_in_box(goal, 0.5) then
|
or self:move_to(goal, method or "animalia:fly_obstacle_avoidance", 1)then
|
||||||
self:halt()
|
self:halt()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
self:move(goal, method or "animalia:fly_obstacle_avoidance", 1)
|
|
||||||
end
|
end
|
||||||
self:set_action(func)
|
self:set_action(func)
|
||||||
end
|
end
|
||||||
|
@ -485,7 +413,6 @@ end
|
||||||
function animalia.action_boid_walk(self, pos2, timeout, method, speed_factor, anim)
|
function animalia.action_boid_walk(self, pos2, timeout, method, speed_factor, anim)
|
||||||
local boids = creatura.get_boid_members(self.object:get_pos(), 12, self.name)
|
local boids = creatura.get_boid_members(self.object:get_pos(), 12, self.name)
|
||||||
local timer = timeout
|
local timer = timeout
|
||||||
local move_init = false
|
|
||||||
local goal = pos2
|
local goal = pos2
|
||||||
local function func(self)
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
@ -500,19 +427,11 @@ function animalia.action_boid_walk(self, pos2, timeout, method, speed_factor, an
|
||||||
pos2 = get_ground_level(vec_add(pos, vec_multi(boid_dir, 4)), 2)
|
pos2 = get_ground_level(vec_add(pos, vec_multi(boid_dir, 4)), 2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not pos2
|
|
||||||
or (move_init
|
|
||||||
and not self._movement_data.goal) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
if timer <= 0
|
if timer <= 0
|
||||||
or self:pos_in_box({x = goal.x, y = pos.y + 0.1, z = goal.z})
|
or self:move_to(pos2, method or "creatura:obstacle_avoidance", speed_factor or 1, anim or "walk") then
|
||||||
or vec_dist(pos, goal) < 1 then
|
|
||||||
self:halt()
|
self:halt()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
self:move(pos2, method or "creatura:obstacle_avoidance", speed_factor or 1, anim or "walk")
|
|
||||||
move_init = true
|
|
||||||
end
|
end
|
||||||
self:set_action(func)
|
self:set_action(func)
|
||||||
end
|
end
|
||||||
|
@ -547,10 +466,6 @@ function animalia.action_horse_spin(self, speed, anim)
|
||||||
self:set_action(func)
|
self:set_action(func)
|
||||||
end
|
end
|
||||||
|
|
||||||
---------------
|
|
||||||
-- Behaviors --
|
|
||||||
---------------
|
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
-- Register Utilities --
|
-- Register Utilities --
|
||||||
------------------------
|
------------------------
|
||||||
|
@ -564,6 +479,7 @@ creatura.register_utility("animalia:wander", function(self, group)
|
||||||
local group_tick = 1
|
local group_tick = 1
|
||||||
local function func(self)
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
local goal
|
local goal
|
||||||
local move = random(move_probability) < 2
|
local move = random(move_probability) < 2
|
||||||
|
@ -615,6 +531,7 @@ creatura.register_utility("animalia:skittish_wander", function(self)
|
||||||
local avoid_tick = 1
|
local avoid_tick = 1
|
||||||
local function func(self)
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
local goal
|
local goal
|
||||||
local move = random(move_probability) < 2
|
local move = random(move_probability) < 2
|
||||||
|
@ -661,6 +578,7 @@ creatura.register_utility("animalia:skittish_boid_wander", function(self)
|
||||||
local force_move = false
|
local force_move = false
|
||||||
local function func(self)
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local goal
|
local goal
|
||||||
if self:timer(3) then
|
if self:timer(3) then
|
||||||
local range = self.tracking_range * 0.5
|
local range = self.tracking_range * 0.5
|
||||||
|
@ -717,6 +635,7 @@ creatura.register_utility("animalia:boid_wander", function(self, group)
|
||||||
local group_tick = 1
|
local group_tick = 1
|
||||||
local function func(self)
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
local goal
|
local goal
|
||||||
local move = random(move_probability) < 2
|
local move = random(move_probability) < 2
|
||||||
|
@ -765,7 +684,8 @@ creatura.register_utility("animalia:wander_water_surface", function(self)
|
||||||
local function func(self)
|
local function func(self)
|
||||||
if not self.in_liquid then return true end
|
if not self.in_liquid then return true end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
local random_goal = get_wander_pos_3d(self, 2)
|
if not pos then return end
|
||||||
|
local random_goal = self:get_wander_pos_3d(1, 3)
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
if self.lasso_pos
|
if self.lasso_pos
|
||||||
and vec_dist(pos, self.lasso_pos) > 10 then
|
and vec_dist(pos, self.lasso_pos) > 10 then
|
||||||
|
@ -789,6 +709,7 @@ creatura.register_utility("animalia:eat_from_turf", function(self)
|
||||||
local action_init = false
|
local action_init = false
|
||||||
local function func(self)
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local look_dir = yaw2dir(self.object:get_yaw())
|
local look_dir = yaw2dir(self.object:get_yaw())
|
||||||
local under = vec_add(pos, vec_multi(look_dir, self.width))
|
local under = vec_add(pos, vec_multi(look_dir, self.width))
|
||||||
under.y = pos.y - 0.5
|
under.y = pos.y - 0.5
|
||||||
|
@ -845,6 +766,7 @@ end)
|
||||||
creatura.register_utility("animalia:eat_bug_nodes", function(self)
|
creatura.register_utility("animalia:eat_bug_nodes", function(self)
|
||||||
local timer = 0.2
|
local timer = 0.2
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local food = minetest.find_nodes_in_area(vec_sub(pos, 1.5), vec_add(pos, 1.5), self.follow)
|
local food = minetest.find_nodes_in_area(vec_sub(pos, 1.5), vec_add(pos, 1.5), self.follow)
|
||||||
local function func(self)
|
local function func(self)
|
||||||
pos = self.object:get_pos()
|
pos = self.object:get_pos()
|
||||||
|
@ -898,6 +820,7 @@ creatura.register_utility("animalia:swim_to_land", function(self)
|
||||||
end
|
end
|
||||||
if tpos then
|
if tpos then
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local yaw = self.object:get_yaw()
|
local yaw = self.object:get_yaw()
|
||||||
local tyaw = minetest.dir_to_yaw(vec_dir(pos, tpos))
|
local tyaw = minetest.dir_to_yaw(vec_dir(pos, tpos))
|
||||||
if abs(tyaw - yaw) > 0.1 then
|
if abs(tyaw - yaw) > 0.1 then
|
||||||
|
@ -941,6 +864,7 @@ creatura.register_utility("animalia:flee_from_player", function(self, player, ra
|
||||||
local target_alive, line_of_sight, tpos = self:get_target(player)
|
local target_alive, line_of_sight, tpos = self:get_target(player)
|
||||||
if not target_alive then return true end
|
if not target_alive then return true end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local dir = vec_dir(pos, tpos)
|
local dir = vec_dir(pos, tpos)
|
||||||
local escape_pos = vec_add(pos, vec_multi(vec_add(dir, {x = random(-10, 10) * 0.1, y = 0, z = random(-10, 10) * 0.1}), -3))
|
local escape_pos = vec_add(pos, vec_multi(vec_add(dir, {x = random(-10, 10) * 0.1, y = 0, z = random(-10, 10) * 0.1}), -3))
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
|
@ -973,6 +897,7 @@ creatura.register_utility("animalia:boid_flee_from_player", function(self, playe
|
||||||
local target_alive, line_of_sight, tpos = self:get_target(player)
|
local target_alive, line_of_sight, tpos = self:get_target(player)
|
||||||
if not target_alive then return true end
|
if not target_alive then return true end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local dir = vec_dir(pos, tpos)
|
local dir = vec_dir(pos, tpos)
|
||||||
local escape_pos = vec_add(pos, vec_multi(vec_add(dir, {x = random(-10, 10) * 0.1, y = 0, z = random(-10, 10) * 0.1}), -3))
|
local escape_pos = vec_add(pos, vec_multi(vec_add(dir, {x = random(-10, 10) * 0.1, y = 0, z = random(-10, 10) * 0.1}), -3))
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
|
@ -995,6 +920,7 @@ end)
|
||||||
creatura.register_utility("animalia:flee_to_water", function(self)
|
creatura.register_utility("animalia:flee_to_water", function(self)
|
||||||
local function func(self)
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local water = minetest.find_nodes_in_area_under_air(vec_sub(pos, 3), vec_add(pos, 3), {"default:water_source"})
|
local water = minetest.find_nodes_in_area_under_air(vec_sub(pos, 3), vec_add(pos, 3), {"default:water_source"})
|
||||||
if water[1]
|
if water[1]
|
||||||
and vec_dist(pos, water[1]) < 0.5 then
|
and vec_dist(pos, water[1]) < 0.5 then
|
||||||
|
@ -1020,6 +946,7 @@ creatura.register_utility("animalia:follow_player", function(self, player, force
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local dist = vec_dist(pos, tpos)
|
local dist = vec_dist(pos, tpos)
|
||||||
if dist > self.tracking_range then
|
if dist > self.tracking_range then
|
||||||
return true
|
return true
|
||||||
|
@ -1050,6 +977,7 @@ creatura.register_utility("animalia:sporadic_flee", function(self)
|
||||||
end
|
end
|
||||||
local function func(self)
|
local function func(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local random_goal = {
|
local random_goal = {
|
||||||
x = pos.x + random(-4, 4),
|
x = pos.x + random(-4, 4),
|
||||||
y = pos.y,
|
y = pos.y,
|
||||||
|
@ -1088,6 +1016,7 @@ creatura.register_utility("animalia:mammal_breed", function(self)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local pos = self:get_center_pos()
|
local pos = self:get_center_pos()
|
||||||
|
if not pos then return end
|
||||||
local tpos = mate:get_pos()
|
local tpos = mate:get_pos()
|
||||||
local dist = vec_dist(pos, tpos) - abs(self:get_hitbox(self)[4])
|
local dist = vec_dist(pos, tpos) - abs(self:get_hitbox(self)[4])
|
||||||
if dist < 1.75 then
|
if dist < 1.75 then
|
||||||
|
@ -1129,6 +1058,7 @@ creatura.register_utility("animalia:horse_breed", function(self)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local pos = self:get_center_pos()
|
local pos = self:get_center_pos()
|
||||||
|
if not pos then return end
|
||||||
local tpos = mate:get_pos()
|
local tpos = mate:get_pos()
|
||||||
local dist = vec_dist(pos, tpos) - abs(self:get_hitbox(self)[4])
|
local dist = vec_dist(pos, tpos) - abs(self:get_hitbox(self)[4])
|
||||||
if dist < 1.75 then
|
if dist < 1.75 then
|
||||||
|
@ -1179,6 +1109,7 @@ creatura.register_utility("animalia:bird_breed", function(self)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local pos = self:get_center_pos()
|
local pos = self:get_center_pos()
|
||||||
|
if not pos then return end
|
||||||
local tpos = mate:get_pos()
|
local tpos = mate:get_pos()
|
||||||
local dist = vec_dist(pos, tpos) - abs(self:get_hitbox(self)[4])
|
local dist = vec_dist(pos, tpos) - abs(self:get_hitbox(self)[4])
|
||||||
if dist < 1.75 then
|
if dist < 1.75 then
|
||||||
|
@ -1240,6 +1171,7 @@ creatura.register_utility("animalia:attack", function(self, target, group)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local dist = vec_dist(pos, tpos)
|
local dist = vec_dist(pos, tpos)
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
if punch_init then return true end
|
if punch_init then return true end
|
||||||
|
@ -1288,6 +1220,7 @@ creatura.register_utility("animalia:aerial_flock", function(self, scale)
|
||||||
or (dist2floor < 2
|
or (dist2floor < 2
|
||||||
or dist2ceil < 2) then
|
or dist2ceil < 2) then
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local pos2 = self:get_wander_pos_3d(1, range)
|
local pos2 = self:get_wander_pos_3d(1, range)
|
||||||
if dist2ceil < 2 then
|
if dist2ceil < 2 then
|
||||||
pos2.y = pos.y - 1
|
pos2.y = pos.y - 1
|
||||||
|
@ -1328,6 +1261,7 @@ creatura.register_utility("animalia:aerial_swarm", function(self, scale)
|
||||||
or (dist2floor < 2
|
or (dist2floor < 2
|
||||||
or dist2ceil < 2) then
|
or dist2ceil < 2) then
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local pos2 = self:get_wander_pos_3d(1, 3)
|
local pos2 = self:get_wander_pos_3d(1, 3)
|
||||||
if dist2floor < 2 then
|
if dist2floor < 2 then
|
||||||
pos2.y = pos.y + 1
|
pos2.y = pos.y + 1
|
||||||
|
@ -1349,6 +1283,7 @@ creatura.register_utility("animalia:land", function(self, scale)
|
||||||
if node and get_node_def(node.name).drawtype == "liquid" then self.is_landed = false return true end
|
if node and get_node_def(node.name).drawtype == "liquid" then self.is_landed = false return true end
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local offset = random(2 * scale, 3 * scale)
|
local offset = random(2 * scale, 3 * scale)
|
||||||
if random(2) < 2 then
|
if random(2) < 2 then
|
||||||
offset = offset * -1
|
offset = offset * -1
|
||||||
|
@ -1370,6 +1305,7 @@ creatura.register_utility("animalia:return_to_nest", function(self)
|
||||||
local function func(self)
|
local function func(self)
|
||||||
if not self.home_position then return true end
|
if not self.home_position then return true end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local pos2 = self.home_position
|
local pos2 = self.home_position
|
||||||
local dist = vec_dist(pos, {x = pos2.x, y = pos.y, z = pos2.z})
|
local dist = vec_dist(pos, {x = pos2.x, y = pos.y, z = pos2.z})
|
||||||
if dist < 4
|
if dist < 4
|
||||||
|
@ -1389,6 +1325,7 @@ end)
|
||||||
|
|
||||||
creatura.register_utility("animalia:schooling", function(self)
|
creatura.register_utility("animalia:schooling", function(self)
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local water = minetest.find_nodes_in_area(vector.subtract(pos, 5), vector.add(pos, 5), {"group:water"})
|
local water = minetest.find_nodes_in_area(vector.subtract(pos, 5), vector.add(pos, 5), {"group:water"})
|
||||||
local function func(self)
|
local function func(self)
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
|
@ -1433,6 +1370,7 @@ creatura.register_utility("animalia:die", function(self)
|
||||||
timer = timer - self.dtime
|
timer = timer - self.dtime
|
||||||
if timer <= 0 then
|
if timer <= 0 then
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
minetest.add_particlespawner({
|
minetest.add_particlespawner({
|
||||||
amount = 8,
|
amount = 8,
|
||||||
time = 0.25,
|
time = 0.25,
|
||||||
|
@ -1467,6 +1405,7 @@ end)
|
||||||
creatura.register_utility("animalia:find_and_break_glass_vessels", function(self)
|
creatura.register_utility("animalia:find_and_break_glass_vessels", function(self)
|
||||||
local timer = 12
|
local timer = 12
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local pos2 = nil
|
local pos2 = nil
|
||||||
local nodes = minetest.find_nodes_in_area(
|
local nodes = minetest.find_nodes_in_area(
|
||||||
vector.subtract(pos, 8),
|
vector.subtract(pos, 8),
|
||||||
|
@ -1506,6 +1445,7 @@ creatura.register_utility("animalia:walk_ahead_of_player", function(self, player
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local tpos = player:get_pos()
|
local tpos = player:get_pos()
|
||||||
local dir = player:get_look_dir()
|
local dir = player:get_look_dir()
|
||||||
tpos.x = tpos.x + dir.x
|
tpos.x = tpos.x + dir.x
|
||||||
|
@ -1537,6 +1477,7 @@ creatura.register_utility("animalia:return_to_home", function(self)
|
||||||
local function func(self)
|
local function func(self)
|
||||||
if not self.home_position then return true end
|
if not self.home_position then return true end
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local pos2 = self.home_position
|
local pos2 = self.home_position
|
||||||
local dist = vec_dist(pos, pos2)
|
local dist = vec_dist(pos, pos2)
|
||||||
if dist < 2 then
|
if dist < 2 then
|
||||||
|
@ -1557,6 +1498,7 @@ creatura.register_utility("animalia:find_home", function(self)
|
||||||
local init = false
|
local init = false
|
||||||
local tpos = nil
|
local tpos = nil
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
if not pos then return end
|
||||||
local range = self.tracking_range
|
local range = self.tracking_range
|
||||||
local ceiling = get_ceiling_positions(pos, range / 2)
|
local ceiling = get_ceiling_positions(pos, range / 2)
|
||||||
local iter = 1
|
local iter = 1
|
||||||
|
@ -1568,7 +1510,7 @@ creatura.register_utility("animalia:find_home", function(self)
|
||||||
end
|
end
|
||||||
pos = self.object:get_pos()
|
pos = self.object:get_pos()
|
||||||
if not self:get_action() then
|
if not self:get_action() then
|
||||||
local pos2 = get_wander_pos_3d(self, range)
|
local pos2 = self:get_wander_pos_3d(1, range)
|
||||||
local dist2floor = creatura.sensor_floor(self, 5, true)
|
local dist2floor = creatura.sensor_floor(self, 5, true)
|
||||||
local dist2ceil = creatura.sensor_ceil(self, 5, true)
|
local dist2ceil = creatura.sensor_ceil(self, 5, true)
|
||||||
if dist2floor < 4 then
|
if dist2floor < 4 then
|
||||||
|
|
Loading…
Add table
Reference in a new issue