mirror of
https://github.com/ElCeejo/creatura.git
synced 2025-04-30 05:41:46 -04:00
Minor performance and stability improvements
This commit is contained in:
parent
ad475bb790
commit
13ebe1c37d
6 changed files with 1196 additions and 1372 deletions
598
api.lua
598
api.lua
|
@ -6,20 +6,9 @@ creatura.api = {}
|
|||
|
||||
-- Math --
|
||||
|
||||
local pi = math.pi
|
||||
local pi2 = pi * 2
|
||||
local abs = math.abs
|
||||
local floor = math.floor
|
||||
local random = math.random
|
||||
|
||||
local sin = math.sin
|
||||
local cos = math.cos
|
||||
local atan2 = math.atan2
|
||||
|
||||
local function diff(a, b) -- Get difference between 2 angles
|
||||
return math.atan2(math.sin(b - a), math.cos(b - a))
|
||||
end
|
||||
|
||||
local function clamp(val, min, max)
|
||||
if val < min then
|
||||
val = min
|
||||
|
@ -29,25 +18,18 @@ local function clamp(val, min, max)
|
|||
return val
|
||||
end
|
||||
|
||||
local vec_dir = vector.direction
|
||||
local vec_dist = vector.distance
|
||||
local vec_multi = vector.multiply
|
||||
local vec_sub = vector.subtract
|
||||
local vec_equals = vector.equals
|
||||
local vec_add = vector.add
|
||||
|
||||
local function vec_center(v)
|
||||
return {x = floor(v.x + 0.5), y = floor(v.y + 0.5), z = floor(v.z + 0.5)}
|
||||
return {x = floor(v.x + 0.5), y = floor(v.y + 0.5), z = floor(v.z + 0.5)}
|
||||
end
|
||||
|
||||
local function vec_raise(v, n)
|
||||
if not v then return end
|
||||
return {x = v.x, y = v.y + n, z = v.z}
|
||||
end
|
||||
|
||||
local function dist_2d(pos1, pos2)
|
||||
local a = {x = pos1.x, y = 0, z = pos1.z}
|
||||
local b = {x = pos2.x, y = 0, z = pos2.z}
|
||||
return vec_dist(a, b)
|
||||
if not v then return end
|
||||
return {x = v.x, y = v.y + n, z = v.z}
|
||||
end
|
||||
|
||||
---------------
|
||||
|
@ -55,12 +37,12 @@ end
|
|||
---------------
|
||||
|
||||
local function is_value_in_table(tbl, val)
|
||||
for _, v in pairs(tbl) do
|
||||
if v == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
for _, v in pairs(tbl) do
|
||||
if v == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-----------------------
|
||||
|
@ -72,7 +54,7 @@ end
|
|||
creatura.registered_movement_methods = {}
|
||||
|
||||
function creatura.register_movement_method(name, func)
|
||||
creatura.registered_movement_methods[name] = func
|
||||
creatura.registered_movement_methods[name] = func
|
||||
end
|
||||
|
||||
-- Utility Behaviors --
|
||||
|
@ -80,7 +62,7 @@ end
|
|||
creatura.registered_utilities = {}
|
||||
|
||||
function creatura.register_utility(name, func)
|
||||
creatura.registered_utilities[name] = func
|
||||
creatura.registered_utilities[name] = func
|
||||
end
|
||||
|
||||
-- Sensors --
|
||||
|
@ -93,7 +75,7 @@ function creatura.get_node_height_from_def(name)
|
|||
if def.walkable then
|
||||
if def.drawtype == "nodebox" then
|
||||
if def.node_box
|
||||
and def.node_box.type == "fixed" then
|
||||
and def.node_box.type == "fixed" then
|
||||
if type(def.node_box.fixed[1]) == "number" then
|
||||
return 0.5 + def.node_box.fixed[5]
|
||||
elseif type(def.node_box.fixed[1]) == "table" then
|
||||
|
@ -113,234 +95,232 @@ function creatura.get_node_height_from_def(name)
|
|||
end
|
||||
|
||||
function creatura.get_node_def(node) -- Node can be name or pos
|
||||
if type(node) == "table" then
|
||||
node = minetest.get_node(node).name
|
||||
end
|
||||
local def = minetest.registered_nodes[node] or default_node_def
|
||||
if def.walkable
|
||||
and creatura.get_node_height_from_def(node) < 0.26 then
|
||||
def.walkable = false -- workaround for nodes like snow
|
||||
end
|
||||
return def
|
||||
if type(node) == "table" then
|
||||
node = minetest.get_node(node).name
|
||||
end
|
||||
local def = minetest.registered_nodes[node] or default_node_def
|
||||
if def.walkable
|
||||
and creatura.get_node_height_from_def(node) < 0.26 then
|
||||
def.walkable = false -- workaround for nodes like snow
|
||||
end
|
||||
return def
|
||||
end
|
||||
|
||||
function creatura.get_ground_level(pos2, max_diff)
|
||||
local node = minetest.get_node(pos2)
|
||||
local node_under = minetest.get_node({
|
||||
x = pos2.x,
|
||||
y = pos2.y - 1,
|
||||
z = pos2.z
|
||||
})
|
||||
local walkable = creatura.get_node_def(node_under.name).walkable and not creatura.get_node_def(node.name).walkable
|
||||
if walkable then
|
||||
return pos2
|
||||
end
|
||||
local diff = 0
|
||||
if not creatura.get_node_def(node_under.name).walkable then
|
||||
for i = 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 i = 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
|
||||
return pos2
|
||||
local node = minetest.get_node(pos2)
|
||||
local node_under = minetest.get_node({
|
||||
x = pos2.x,
|
||||
y = pos2.y - 1,
|
||||
z = pos2.z
|
||||
})
|
||||
local walkable = creatura.get_node_def(node_under.name).walkable and not creatura.get_node_def(node.name).walkable
|
||||
if walkable then
|
||||
return pos2
|
||||
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
|
||||
return pos2
|
||||
end
|
||||
|
||||
function creatura.is_pos_moveable(pos, width, height)
|
||||
local pos1 = {
|
||||
x = pos.x - (width + 0.2),
|
||||
y = pos.y,
|
||||
z = pos.z - (width + 0.2),
|
||||
}
|
||||
local pos2 = {
|
||||
x = pos.x + (width + 0.2),
|
||||
y = pos.y,
|
||||
z = pos.z + (width + 0.2),
|
||||
}
|
||||
for z = pos1.z, pos2.z do
|
||||
for x = pos1.x, pos2.x do
|
||||
local pos3 = {x = x, y = pos.y + height, z = z}
|
||||
local pos4 = {x = x, y = pos.y + 0.01, z = z}
|
||||
local ray = minetest.raycast(pos3, pos4, false, false)
|
||||
for pointed_thing in ray do
|
||||
if pointed_thing.type == "node" then
|
||||
local name = minetest.get_node(pointed_thing.under).name
|
||||
if creatura.get_node_def(name).walkable then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
local pos1 = {
|
||||
x = pos.x - (width + 0.2),
|
||||
y = pos.y,
|
||||
z = pos.z - (width + 0.2),
|
||||
}
|
||||
local pos2 = {
|
||||
x = pos.x + (width + 0.2),
|
||||
y = pos.y,
|
||||
z = pos.z + (width + 0.2),
|
||||
}
|
||||
for z = pos1.z, pos2.z do
|
||||
for x = pos1.x, pos2.x do
|
||||
local pos3 = {x = x, y = pos.y + height, z = z}
|
||||
local pos4 = {x = x, y = pos.y + 0.01, z = z}
|
||||
local ray = minetest.raycast(pos3, pos4, false, false)
|
||||
for pointed_thing in ray do
|
||||
if pointed_thing.type == "node" then
|
||||
local name = minetest.get_node(pointed_thing.under).name
|
||||
if creatura.get_node_def(name).walkable then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local moveable = creatura.is_pos_moveable
|
||||
|
||||
function creatura.fast_ray_sight(pos1, pos2, water)
|
||||
local ray = minetest.raycast(pos1, pos2, false, water or false)
|
||||
for pointed_thing in ray do
|
||||
if pointed_thing.type == "node" then
|
||||
return false, vec_dist(pos1, pointed_thing.intersection_point), pointed_thing.ref
|
||||
end
|
||||
end
|
||||
return true, vec_dist(pos1, pos2)
|
||||
local ray = minetest.raycast(pos1, pos2, false, water or false)
|
||||
for pointed_thing in ray do
|
||||
if pointed_thing.type == "node" then
|
||||
return false, vec_dist(pos1, pointed_thing.intersection_point), pointed_thing.ref
|
||||
end
|
||||
end
|
||||
return true, vec_dist(pos1, pos2)
|
||||
end
|
||||
|
||||
local fast_ray_sight = creatura.fast_ray_sight
|
||||
|
||||
function creatura.get_next_move(self, pos2)
|
||||
local last_move = self._movement_data.last_move
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
local pos = self.object:get_pos()
|
||||
pos = {
|
||||
x = floor(pos.x),
|
||||
y = pos.y + 0.01,
|
||||
z = floor(pos.z)
|
||||
}
|
||||
pos.y = pos.y + 0.01
|
||||
if last_move
|
||||
and last_move.pos then
|
||||
local last_call = minetest.get_position_from_hash(last_move.pos)
|
||||
local last_move = minetest.get_position_from_hash(last_move.move)
|
||||
if vector.equals(vec_center(last_call), vec_center(pos)) then
|
||||
return last_move
|
||||
end
|
||||
end
|
||||
local neighbors = {
|
||||
vec_add(pos, {x = 1, y = 0, z = 0}),
|
||||
vec_add(pos, {x = 1, y = 0, z = 1}),
|
||||
vec_add(pos, {x = 0, y = 0, z = 1}),
|
||||
vec_add(pos, {x = -1, y = 0, z = 1}),
|
||||
vec_add(pos, {x = -1, y = 0, z = 0}),
|
||||
vec_add(pos, {x = -1, y = 0, z = -1}),
|
||||
vec_add(pos, {x = 0, y = 0, z = -1}),
|
||||
vec_add(pos, {x = 1, y = 0, z = -1})
|
||||
}
|
||||
local _next
|
||||
table.sort(neighbors, function(a, b)
|
||||
return vec_dist(a, pos2) < vec_dist(b, pos2)
|
||||
end)
|
||||
for i = 1, #neighbors do
|
||||
local neighbor = neighbors[i]
|
||||
local can_move = fast_ray_sight(pos, neighbor)
|
||||
if vector.equals(neighbor, pos2) then
|
||||
can_move = true
|
||||
end
|
||||
if can_move
|
||||
and not moveable(neighbor, width, height) then
|
||||
can_move = false
|
||||
if moveable(vec_raise(neighbor, 0.5), width, height) then
|
||||
can_move = true
|
||||
end
|
||||
end
|
||||
if can_move
|
||||
and not self:is_pos_safe(neighbor) then
|
||||
can_move = false
|
||||
end
|
||||
if can_move then
|
||||
_next = vec_raise(neighbor, 0.1)
|
||||
break
|
||||
end
|
||||
end
|
||||
if _next then
|
||||
self._movement_data.last_move = {
|
||||
pos = minetest.hash_node_position(pos),
|
||||
move = minetest.hash_node_position(_next)
|
||||
}
|
||||
_next = {
|
||||
x = floor(_next.x),
|
||||
y = _next.y,
|
||||
z = floor(_next.z)
|
||||
}
|
||||
end
|
||||
return _next
|
||||
local last_move = self._movement_data.last_move
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
local pos = self.object:get_pos()
|
||||
pos = {
|
||||
x = floor(pos.x),
|
||||
y = pos.y + 0.01,
|
||||
z = floor(pos.z)
|
||||
}
|
||||
pos.y = pos.y + 0.01
|
||||
if last_move
|
||||
and last_move.pos then
|
||||
local last_call = minetest.get_position_from_hash(last_move.pos)
|
||||
last_move = minetest.get_position_from_hash(last_move.move)
|
||||
if vec_equals(vec_center(last_call), vec_center(pos)) then
|
||||
return last_move
|
||||
end
|
||||
end
|
||||
local neighbors = {
|
||||
vec_add(pos, {x = 1, y = 0, z = 0}),
|
||||
vec_add(pos, {x = 1, y = 0, z = 1}),
|
||||
vec_add(pos, {x = 0, y = 0, z = 1}),
|
||||
vec_add(pos, {x = -1, y = 0, z = 1}),
|
||||
vec_add(pos, {x = -1, y = 0, z = 0}),
|
||||
vec_add(pos, {x = -1, y = 0, z = -1}),
|
||||
vec_add(pos, {x = 0, y = 0, z = -1}),
|
||||
vec_add(pos, {x = 1, y = 0, z = -1})
|
||||
}
|
||||
local _next
|
||||
table.sort(neighbors, function(a, b)
|
||||
return vec_dist(a, pos2) < vec_dist(b, pos2)
|
||||
end)
|
||||
for i = 1, #neighbors do
|
||||
local neighbor = neighbors[i]
|
||||
local can_move = fast_ray_sight(pos, neighbor)
|
||||
if vec_equals(neighbor, pos2) then
|
||||
can_move = true
|
||||
end
|
||||
if can_move
|
||||
and not moveable(neighbor, width, height) then
|
||||
can_move = false
|
||||
if moveable(vec_raise(neighbor, 0.5), width, height) then
|
||||
can_move = true
|
||||
end
|
||||
end
|
||||
if can_move
|
||||
and not self:is_pos_safe(neighbor) then
|
||||
can_move = false
|
||||
end
|
||||
if can_move then
|
||||
_next = vec_raise(neighbor, 0.1)
|
||||
break
|
||||
end
|
||||
end
|
||||
if _next then
|
||||
self._movement_data.last_move = {
|
||||
pos = minetest.hash_node_position(pos),
|
||||
move = minetest.hash_node_position(_next)
|
||||
}
|
||||
_next = {
|
||||
x = floor(_next.x),
|
||||
y = _next.y,
|
||||
z = floor(_next.z)
|
||||
}
|
||||
end
|
||||
return _next
|
||||
end
|
||||
|
||||
function creatura.get_next_move_3d(self, pos2)
|
||||
local last_move = self._movement_data.last_move
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
local scan_width = width * 2
|
||||
local pos = self.object:get_pos()
|
||||
pos.y = pos.y + 0.5
|
||||
if last_move
|
||||
and last_move.pos then
|
||||
local last_call = minetest.get_position_from_hash(last_move.pos)
|
||||
local last_move = minetest.get_position_from_hash(last_move.move)
|
||||
if vector.equals(vec_center(last_call), vec_center(pos)) then
|
||||
return last_move
|
||||
end
|
||||
end
|
||||
local neighbors = {
|
||||
vec_add(pos, {x = scan_width, y = 0, z = 0}),
|
||||
vec_add(pos, {x = scan_width, y = 0, z = scan_width}),
|
||||
vec_add(pos, {x = 0, y = 0, z = scan_width}),
|
||||
vec_add(pos, {x = -scan_width, y = 0, z = scan_width}),
|
||||
vec_add(pos, {x = -scan_width, y = 0, z = 0}),
|
||||
vec_add(pos, {x = -scan_width, y = 0, z = -scan_width}),
|
||||
vec_add(pos, {x = 0, y = 0, z = -scan_width}),
|
||||
vec_add(pos, {x = scan_width, y = 0, z = -scan_width})
|
||||
}
|
||||
local next
|
||||
table.sort(neighbors, function(a, b)
|
||||
return vec_dist(a, pos2) < vec_dist(b, pos2)
|
||||
end)
|
||||
for i = 1, #neighbors do
|
||||
local neighbor = neighbors[i]
|
||||
local can_move = fast_ray_sight({x = pos.x, y = neighbor.y, z = pos.z}, neighbor)
|
||||
if not moveable(vec_raise(neighbor, 0.6), width, height) then
|
||||
can_move = false
|
||||
end
|
||||
if vector.equals(neighbor, pos2) then
|
||||
can_move = true
|
||||
end
|
||||
local dist = vec_dist(neighbor, pos2)
|
||||
if can_move then
|
||||
next = neighbor
|
||||
break
|
||||
end
|
||||
end
|
||||
if next then
|
||||
self._movement_data.last_move = {
|
||||
pos = minetest.hash_node_position(pos),
|
||||
move = minetest.hash_node_position(next)
|
||||
}
|
||||
end
|
||||
return vec_raise(next, clamp((pos2.y - pos.y) + -0.6, -1, 1))
|
||||
local last_move = self._movement_data.last_move
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
local scan_width = width * 2
|
||||
local pos = self.object:get_pos()
|
||||
pos.y = pos.y + 0.5
|
||||
if last_move
|
||||
and last_move.pos then
|
||||
local last_call = minetest.get_position_from_hash(last_move.pos)
|
||||
last_move = minetest.get_position_from_hash(last_move.move)
|
||||
if vec_equals(vec_center(last_call), vec_center(pos)) then
|
||||
return last_move
|
||||
end
|
||||
end
|
||||
local neighbors = {
|
||||
vec_add(pos, {x = scan_width, y = 0, z = 0}),
|
||||
vec_add(pos, {x = scan_width, y = 0, z = scan_width}),
|
||||
vec_add(pos, {x = 0, y = 0, z = scan_width}),
|
||||
vec_add(pos, {x = -scan_width, y = 0, z = scan_width}),
|
||||
vec_add(pos, {x = -scan_width, y = 0, z = 0}),
|
||||
vec_add(pos, {x = -scan_width, y = 0, z = -scan_width}),
|
||||
vec_add(pos, {x = 0, y = 0, z = -scan_width}),
|
||||
vec_add(pos, {x = scan_width, y = 0, z = -scan_width})
|
||||
}
|
||||
local next
|
||||
table.sort(neighbors, function(a, b)
|
||||
return vec_dist(a, pos2) < vec_dist(b, pos2)
|
||||
end)
|
||||
for i = 1, #neighbors do
|
||||
local neighbor = neighbors[i]
|
||||
local can_move = fast_ray_sight({x = pos.x, y = neighbor.y, z = pos.z}, neighbor)
|
||||
if not moveable(vec_raise(neighbor, 0.6), width, height) then
|
||||
can_move = false
|
||||
end
|
||||
if vec_equals(neighbor, pos2) then
|
||||
can_move = true
|
||||
end
|
||||
if can_move then
|
||||
next = neighbor
|
||||
break
|
||||
end
|
||||
end
|
||||
if next then
|
||||
self._movement_data.last_move = {
|
||||
pos = minetest.hash_node_position(pos),
|
||||
move = minetest.hash_node_position(next)
|
||||
}
|
||||
end
|
||||
return vec_raise(next, clamp((pos2.y - pos.y) + -0.6, -1, 1))
|
||||
end
|
||||
|
||||
function creatura.sensor_floor(self, range, water)
|
||||
local pos = self.object:get_pos()
|
||||
local pos2 = vec_raise(pos, -range)
|
||||
local _, dist, node = fast_ray_sight(pos, pos2, water or false)
|
||||
return dist, node
|
||||
local pos = self.object:get_pos()
|
||||
local pos2 = vec_raise(pos, -range)
|
||||
local _, dist, node = fast_ray_sight(pos, pos2, water or false)
|
||||
return dist, node
|
||||
end
|
||||
|
||||
function creatura.sensor_ceil(self, range, water)
|
||||
local pos = vec_raise(self.object:get_pos(), self.height)
|
||||
local pos2 = vec_raise(pos, range)
|
||||
local _, dist, node = fast_ray_sight(pos, pos2, water or false)
|
||||
return dist, node
|
||||
local pos = vec_raise(self.object:get_pos(), self.height)
|
||||
local pos2 = vec_raise(pos, range)
|
||||
local _, dist, node = fast_ray_sight(pos, pos2, water or false)
|
||||
return dist, node
|
||||
end
|
||||
|
||||
-- Misc
|
||||
|
@ -355,69 +335,69 @@ function creatura.is_valid(mob)
|
|||
if mob:get_yaw() then return mob end
|
||||
end
|
||||
end
|
||||
return false
|
||||
return false
|
||||
end
|
||||
|
||||
function creatura.is_alive(mob)
|
||||
if not creatura.is_valid(mob) then
|
||||
return false
|
||||
end
|
||||
if type(mob) == "table" then
|
||||
return mob.hp > 0
|
||||
end
|
||||
if mob:is_player() then
|
||||
return mob:get_hp() > 0
|
||||
else
|
||||
local ent = mob:get_luaentity()
|
||||
return ent and ent.hp and ent.hp > 0
|
||||
end
|
||||
if not creatura.is_valid(mob) then
|
||||
return false
|
||||
end
|
||||
if type(mob) == "table" then
|
||||
return mob.hp > 0
|
||||
end
|
||||
if mob:is_player() then
|
||||
return mob:get_hp() > 0
|
||||
else
|
||||
local ent = mob:get_luaentity()
|
||||
return ent and ent.hp and ent.hp > 0
|
||||
end
|
||||
end
|
||||
|
||||
function creatura.get_nearby_player(self)
|
||||
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
|
||||
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
|
||||
for _, object in ipairs(objects) do
|
||||
if object:is_player()
|
||||
and creatura.is_alive(object) then
|
||||
return object
|
||||
end
|
||||
and creatura.is_alive(object) then
|
||||
return object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function creatura.get_nearby_players(self)
|
||||
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
|
||||
local nearby = {}
|
||||
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
|
||||
local nearby = {}
|
||||
for _, object in ipairs(objects) do
|
||||
if object:is_player()
|
||||
and creatura.is_alive(object) then
|
||||
table.insert(nearby, object)
|
||||
end
|
||||
and creatura.is_alive(object) then
|
||||
table.insert(nearby, object)
|
||||
end
|
||||
end
|
||||
return nearby
|
||||
end
|
||||
|
||||
function creatura.get_nearby_entity(self, name)
|
||||
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
|
||||
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
|
||||
for _, object in ipairs(objects) do
|
||||
if creatura.is_alive(object)
|
||||
and not object:is_player()
|
||||
and object ~= self.object
|
||||
and object:get_luaentity().name == name then
|
||||
return object
|
||||
end
|
||||
and not object:is_player()
|
||||
and object ~= self.object
|
||||
and object:get_luaentity().name == name then
|
||||
return object
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function creatura.get_nearby_entities(self, name)
|
||||
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
|
||||
local nearby = {}
|
||||
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
|
||||
local nearby = {}
|
||||
for _, object in ipairs(objects) do
|
||||
if creatura.is_alive(object)
|
||||
and not object:is_player()
|
||||
and object ~= self.object
|
||||
and object:get_luaentity().name == name then
|
||||
table.insert(nearby, object)
|
||||
end
|
||||
and not object:is_player()
|
||||
and object ~= self.object
|
||||
and object:get_luaentity().name == name then
|
||||
table.insert(nearby, object)
|
||||
end
|
||||
end
|
||||
return nearby
|
||||
end
|
||||
|
@ -429,51 +409,51 @@ end
|
|||
-- Drops --
|
||||
|
||||
function creatura.drop_items(self)
|
||||
if not self.drops then return end
|
||||
for i = 1, #self.drops do
|
||||
local drop_def = self.drops[i]
|
||||
local name = drop_def.name
|
||||
if not name then return end
|
||||
local min_amount = drop_def.min or 1
|
||||
local max_amount = drop_def.max or 2
|
||||
local chance = drop_def.chance or 1
|
||||
local amount = random(min_amount, max_amount)
|
||||
if random(chance) < 2 then
|
||||
local pos = self.object:get_pos()
|
||||
local item = minetest.add_item(pos, ItemStack(name .. " " .. amount))
|
||||
if item then
|
||||
item:add_velocity({
|
||||
x = random(-2, 2),
|
||||
y = 1.5,
|
||||
z = random(-2, 2)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
if not self.drops then return end
|
||||
for i = 1, #self.drops do
|
||||
local drop_def = self.drops[i]
|
||||
local name = drop_def.name
|
||||
if not name then return end
|
||||
local min_amount = drop_def.min or 1
|
||||
local max_amount = drop_def.max or 2
|
||||
local chance = drop_def.chance or 1
|
||||
local amount = random(min_amount, max_amount)
|
||||
if random(chance) < 2 then
|
||||
local pos = self.object:get_pos()
|
||||
local item = minetest.add_item(pos, ItemStack(name .. " " .. amount))
|
||||
if item then
|
||||
item:add_velocity({
|
||||
x = random(-2, 2),
|
||||
y = 1.5,
|
||||
z = random(-2, 2)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- On Punch --
|
||||
|
||||
function creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
|
||||
if not puncher then return end
|
||||
local tool = ""
|
||||
if puncher:is_player() then
|
||||
tool = puncher:get_wielded_item():get_name()
|
||||
end
|
||||
if (self.immune_to
|
||||
and is_value_in_table(self.immune_to, tool)) then
|
||||
return
|
||||
end
|
||||
local dir = vec_dir(puncher:get_pos(), self:get_center_pos())
|
||||
self:apply_knockback(dir)
|
||||
self:hurt(tool_capabilities.damage_groups.fleshy or 2)
|
||||
if random(4) < 2 then
|
||||
self:play_sound("hurt")
|
||||
end
|
||||
if time_from_last_punch > 0.5 then
|
||||
self:play_sound("hit")
|
||||
end
|
||||
self:indicate_damage()
|
||||
if not puncher then return end
|
||||
local tool = ""
|
||||
if puncher:is_player() then
|
||||
tool = puncher:get_wielded_item():get_name()
|
||||
end
|
||||
if (self.immune_to
|
||||
and is_value_in_table(self.immune_to, tool)) then
|
||||
return
|
||||
end
|
||||
local dir = vec_multi(direction, -1)
|
||||
self:apply_knockback(dir)
|
||||
self:hurt((tool_capabilities.damage_groups.fleshy or damage) or 2)
|
||||
if random(4) < 2 then
|
||||
self:play_sound("hurt")
|
||||
end
|
||||
if time_from_last_punch > 0.5 then
|
||||
self:play_sound("hit")
|
||||
end
|
||||
self:indicate_damage()
|
||||
end
|
||||
|
||||
local path = minetest.get_modpath("creatura")
|
||||
|
|
210
boids.lua
210
boids.lua
|
@ -5,60 +5,51 @@
|
|||
local random = math.random
|
||||
|
||||
local function average(tbl)
|
||||
local sum = 0
|
||||
for _,v in pairs(tbl) do -- Get the sum of all numbers in t
|
||||
sum = sum + v
|
||||
end
|
||||
return sum / #tbl
|
||||
local sum = 0
|
||||
for _,v in pairs(tbl) do -- Get the sum of all numbers in t
|
||||
sum = sum + v
|
||||
end
|
||||
return sum / #tbl
|
||||
end
|
||||
|
||||
local function average_angle(tbl)
|
||||
local sum_sin, sum_cos = 0, 0
|
||||
for _, v in pairs(tbl) do
|
||||
sum_sin = sum_sin + math.sin(v)
|
||||
sum_cos = sum_cos + math.cos(v)
|
||||
end
|
||||
return math.atan2(sum_sin, sum_cos)
|
||||
local sum_sin, sum_cos = 0, 0
|
||||
for _, v in pairs(tbl) do
|
||||
sum_sin = sum_sin + math.sin(v)
|
||||
sum_cos = sum_cos + math.cos(v)
|
||||
end
|
||||
return math.atan2(sum_sin, sum_cos)
|
||||
end
|
||||
|
||||
local vec_dist = vector.distance
|
||||
local vec_dir = vector.direction
|
||||
local vec_len = vector.length
|
||||
local vec_add = vector.add
|
||||
local vec_multi = vector.multiply
|
||||
local vec_normal = vector.normalize
|
||||
local vec_divide = vector.divide
|
||||
local function vec_raise(v, n)
|
||||
return {x = v.x, y = v.y + n, z = v.z}
|
||||
end
|
||||
|
||||
local function get_average_pos(vectors)
|
||||
local sum = {x = 0, y = 0, z = 0}
|
||||
for _, vec in pairs(vectors) do sum = vec_add(sum, vec) end
|
||||
return vec_divide(sum, #vectors)
|
||||
local sum = {x = 0, y = 0, z = 0}
|
||||
for _, vec in pairs(vectors) do sum = vec_add(sum, vec) end
|
||||
return vec_divide(sum, #vectors)
|
||||
end
|
||||
|
||||
local function dist_2d(pos1, pos2)
|
||||
local a = vector.new(
|
||||
pos1.x,
|
||||
0,
|
||||
pos1.z
|
||||
)
|
||||
local b = vector.new(
|
||||
pos2.x,
|
||||
0,
|
||||
pos2.z
|
||||
)
|
||||
return vec_dist(a, b)
|
||||
local a = vector.new(
|
||||
pos1.x,
|
||||
0,
|
||||
pos1.z
|
||||
)
|
||||
local b = vector.new(
|
||||
pos2.x,
|
||||
0,
|
||||
pos2.z
|
||||
)
|
||||
return vec_dist(a, b)
|
||||
end
|
||||
|
||||
local yaw2dir = minetest.yaw_to_dir
|
||||
local dir2yaw = minetest.dir_to_yaw
|
||||
|
||||
-- Refresh Boid Leader --
|
||||
|
||||
local last_boid_refresh = minetest.get_us_time()
|
||||
|
||||
-- Get Boid Members --
|
||||
|
||||
-- This function scans within
|
||||
|
@ -70,89 +61,78 @@ local last_boid_refresh = minetest.get_us_time()
|
|||
-- is in the boid.
|
||||
|
||||
function creatura.get_boid_members(pos, radius, name)
|
||||
local objects = minetest.get_objects_inside_radius(pos, radius)
|
||||
if #objects < 2 then return {} end
|
||||
local members = {}
|
||||
local max_boid = minetest.registered_entities[name].max_boids or 7
|
||||
for i = 1, #objects do
|
||||
if #members > max_boid then break end
|
||||
local object = objects[i]
|
||||
if object:get_luaentity()
|
||||
and object:get_luaentity().name == name then
|
||||
object:get_luaentity().boid_heading = math.rad(random(360))
|
||||
table.insert(members, object)
|
||||
end
|
||||
end
|
||||
return members
|
||||
local objects = minetest.get_objects_inside_radius(pos, radius)
|
||||
if #objects < 2 then return {} end
|
||||
local members = {}
|
||||
local max_boid = minetest.registered_entities[name].max_boids or 7
|
||||
for i = 1, #objects do
|
||||
if #members > max_boid then break end
|
||||
local object = objects[i]
|
||||
if object:get_luaentity()
|
||||
and object:get_luaentity().name == name then
|
||||
object:get_luaentity().boid_heading = math.rad(random(360))
|
||||
table.insert(members, object)
|
||||
end
|
||||
end
|
||||
return members
|
||||
end
|
||||
|
||||
-- Calculate Boid angles and offsets.
|
||||
|
||||
local function debugpart(pos, time, part)
|
||||
minetest.add_particle({
|
||||
pos = pos,
|
||||
expirationtime = time or 0.2,
|
||||
size = 8,
|
||||
glow = 16,
|
||||
texture = part or "creatura_particle_red.png"
|
||||
})
|
||||
end
|
||||
|
||||
function creatura.get_boid_angle(self, boid, range) -- calculates boid angle based on seperation, alignment, and cohesion
|
||||
local pos = self.object:get_pos()
|
||||
local boids = boid or creatura.get_boid_members(pos, range or 4, self.name)
|
||||
if #boids < 3 then return end
|
||||
local yaw = self.object:get_yaw()
|
||||
local lift = self.object:get_velocity().y
|
||||
-- Add Boid data to tables
|
||||
local closest_pos
|
||||
local positions = {}
|
||||
local angles = {}
|
||||
local lifts = {}
|
||||
for i = 1, #boids do
|
||||
local boid = boids[i]
|
||||
if boid:get_pos() then
|
||||
local boid_pos = boid:get_pos()
|
||||
local boid_yaw = boid:get_yaw()
|
||||
table.insert(positions, boid_pos)
|
||||
if boid ~= self.object then
|
||||
table.insert(lifts, vec_normal(boid:get_velocity()).y)
|
||||
table.insert(angles, boid:get_yaw())
|
||||
if not closest_pos
|
||||
or vec_dist(pos, boid_pos) < vec_dist(pos, closest_pos) then
|
||||
closest_pos = boid_pos
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if #positions < 3 then return end
|
||||
local center = get_average_pos(positions)
|
||||
local dir2closest = vec_dir(pos, closest_pos)
|
||||
-- Calculate Parameters
|
||||
local alignment = average_angle(angles)
|
||||
center = vec_add(center, yaw2dir(alignment))
|
||||
local dir2center = vec_dir(pos, center)
|
||||
local seperation = yaw + -(dir2yaw(dir2closest) - yaw)
|
||||
local cohesion = dir2yaw(dir2center)
|
||||
local params = {alignment}
|
||||
if self.boid_heading then
|
||||
table.insert(params, yaw + self.boid_heading)
|
||||
end
|
||||
if dist_2d(pos, closest_pos) < (self.boid_seperation or self.width * 3) then
|
||||
table.insert(params, seperation)
|
||||
elseif dist_2d(pos, center) > (#boids * 0.33) * (self.boid_seperation or self.width * 3) then
|
||||
table.insert(params, cohesion)
|
||||
end
|
||||
-- Vertical Params
|
||||
local vert_alignment = average(lifts)
|
||||
local vert_seperation = (self.speed or 2) * -dir2closest.y
|
||||
local vert_cohesion = (self.speed or 2) * dir2center.y
|
||||
local vert_params = {vert_alignment}
|
||||
if math.abs(pos.y - closest_pos.y) < (self.boid_seperation or self.width * 3) then
|
||||
table.insert(vert_params, vert_seperation)
|
||||
elseif math.abs(pos.y - closest_pos.y) > 1.5 * (self.boid_seperation or self.width * 3) then
|
||||
table.insert(vert_params, vert_cohesion + (lift - vert_cohesion) * 0.1)
|
||||
end
|
||||
self.boid_heading = nil
|
||||
return average_angle(params), average_angle(vert_params)
|
||||
function creatura.get_boid_angle(self, _boids, range)
|
||||
local pos = self.object:get_pos()
|
||||
local boids = _boids or creatura.get_boid_members(pos, range or 4, self.name)
|
||||
if #boids < 3 then return end
|
||||
local yaw = self.object:get_yaw()
|
||||
local lift = self.object:get_velocity().y
|
||||
-- Add Boid data to tables
|
||||
local closest_pos
|
||||
local positions = {}
|
||||
local angles = {}
|
||||
local lifts = {}
|
||||
for i = 1, #boids do
|
||||
local boid = boids[i]
|
||||
if boid:get_pos() then
|
||||
local boid_pos = boid:get_pos()
|
||||
table.insert(positions, boid_pos)
|
||||
if boid ~= self.object then
|
||||
table.insert(lifts, vec_normal(boid:get_velocity()).y)
|
||||
table.insert(angles, boid:get_yaw())
|
||||
if not closest_pos
|
||||
or vec_dist(pos, boid_pos) < vec_dist(pos, closest_pos) then
|
||||
closest_pos = boid_pos
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if #positions < 3 then return end
|
||||
local center = get_average_pos(positions)
|
||||
local dir2closest = vec_dir(pos, closest_pos)
|
||||
-- Calculate Parameters
|
||||
local alignment = average_angle(angles)
|
||||
center = vec_add(center, yaw2dir(alignment))
|
||||
local dir2center = vec_dir(pos, center)
|
||||
local seperation = yaw + -(dir2yaw(dir2closest) - yaw)
|
||||
local cohesion = dir2yaw(dir2center)
|
||||
local params = {alignment}
|
||||
if self.boid_heading then
|
||||
table.insert(params, yaw + self.boid_heading)
|
||||
end
|
||||
if dist_2d(pos, closest_pos) < (self.boid_seperation or self.width * 3) then
|
||||
table.insert(params, seperation)
|
||||
elseif dist_2d(pos, center) > (#boids * 0.33) * (self.boid_seperation or self.width * 3) then
|
||||
table.insert(params, cohesion)
|
||||
end
|
||||
-- Vertical Params
|
||||
local vert_alignment = average(lifts)
|
||||
local vert_seperation = (self.speed or 2) * -dir2closest.y
|
||||
local vert_cohesion = (self.speed or 2) * dir2center.y
|
||||
local vert_params = {vert_alignment}
|
||||
if math.abs(pos.y - closest_pos.y) < (self.boid_seperation or self.width * 3) then
|
||||
table.insert(vert_params, vert_seperation)
|
||||
elseif math.abs(pos.y - closest_pos.y) > 1.5 * (self.boid_seperation or self.width * 3) then
|
||||
table.insert(vert_params, vert_cohesion + (lift - vert_cohesion) * 0.1)
|
||||
end
|
||||
self.boid_heading = nil
|
||||
return average_angle(params), average_angle(vert_params)
|
||||
end
|
576
methods.lua
576
methods.lua
|
@ -3,17 +3,17 @@
|
|||
-------------
|
||||
|
||||
local pi = math.pi
|
||||
local pi2 = pi * 2
|
||||
local abs = math.abs
|
||||
local ceil = math.ceil
|
||||
local floor = math.floor
|
||||
local random = math.random
|
||||
local rad = math.rad
|
||||
|
||||
local atan2 = math.atan2
|
||||
local sin = math.sin
|
||||
local cos = math.cos
|
||||
|
||||
local function diff(a, b) -- Get difference between 2 angles
|
||||
return math.atan2(math.sin(b - a), math.cos(b - a))
|
||||
return atan2(sin(b - a), cos(b - a))
|
||||
end
|
||||
|
||||
local function clamp(val, min, max)
|
||||
|
@ -26,62 +26,57 @@ local function clamp(val, min, max)
|
|||
end
|
||||
|
||||
local function vec_center(v)
|
||||
return {x = floor(v.x + 0.5), y = floor(v.y + 0.5), z = floor(v.z + 0.5)}
|
||||
end
|
||||
|
||||
local function vec_raise(v, n)
|
||||
return {x = v.x, y = v.y + n, z = v.z}
|
||||
return {x = floor(v.x + 0.5), y = floor(v.y + 0.5), z = floor(v.z + 0.5)}
|
||||
end
|
||||
|
||||
local vec_dir = vector.direction
|
||||
local vec_dist = vector.distance
|
||||
local vec_multi = vector.multiply
|
||||
local vec_add = vector.add
|
||||
local yaw2dir = minetest.yaw_to_dir
|
||||
local dir2yaw = minetest.dir_to_yaw
|
||||
|
||||
local function debugpart(pos, time, tex)
|
||||
minetest.add_particle({
|
||||
pos = pos,
|
||||
texture = tex or "creatura_particle_red.png",
|
||||
expirationtime = time or 3,
|
||||
glow = 6,
|
||||
size = 12
|
||||
})
|
||||
end
|
||||
--[[local function debugpart(pos, time, tex)
|
||||
minetest.add_particle({
|
||||
pos = pos,
|
||||
texture = tex or "creatura_particle_red.png",
|
||||
expirationtime = time or 3,
|
||||
glow = 6,
|
||||
size = 12
|
||||
})
|
||||
end]]
|
||||
|
||||
---------------------
|
||||
-- Local Utilities --
|
||||
---------------------
|
||||
|
||||
local function get_collision(self, yaw)
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
local pos = self.object:get_pos()
|
||||
pos.y = pos.y + 1
|
||||
local pos2 = vec_add(pos, vec_multi(yaw2dir(yaw), width + 5))
|
||||
for x = -width, width, width / math.ceil(width) do
|
||||
for y = 0, height, height / math.ceil(height) do
|
||||
local vec1 = {
|
||||
x = math.cos(yaw) * ((pos.x + x) - pos.x) + pos.x,
|
||||
y = pos.y + y,
|
||||
z = math.sin(yaw) * ((pos.x + x) - pos.x) + pos.z
|
||||
}
|
||||
local vec2 = {
|
||||
x = math.cos(yaw) * ((pos2.x + x) - pos2.x) + pos2.x,
|
||||
y = vec1.y,
|
||||
z = math.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
|
||||
end
|
||||
end
|
||||
return false
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
local pos = self.object:get_pos()
|
||||
pos.y = pos.y + 1
|
||||
local pos2 = vec_add(pos, vec_multi(yaw2dir(yaw), width + 5))
|
||||
for x = -width, width, width / ceil(width) do
|
||||
for y = 0, height, height / ceil(height) do
|
||||
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
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-------------
|
||||
|
@ -94,59 +89,58 @@ end
|
|||
-- Walk
|
||||
|
||||
function creatura.action_walk(self, pos2, timeout, method, speed_factor, anim)
|
||||
local timer = timeout or 4
|
||||
local move_init = false
|
||||
local function func(self)
|
||||
if not pos2
|
||||
or (move_init
|
||||
and not self._movement_data.goal) then return true end
|
||||
local pos = self.object:get_pos()
|
||||
timer = timer - self.dtime
|
||||
if timer <= 0
|
||||
or self:pos_in_box({x = pos2.x, y = pos.y + 0.1, z = pos2.z}) then
|
||||
self:halt()
|
||||
return true
|
||||
end
|
||||
self:move(pos2, method or "creatura:neighbors", speed_factor or 0.5, anim)
|
||||
move_init = true
|
||||
end
|
||||
self:set_action(func)
|
||||
local timer = timeout or 4
|
||||
local move_init = false
|
||||
local function func(_self)
|
||||
if not pos2
|
||||
or (move_init
|
||||
and not _self._movement_data.goal) then return true end
|
||||
local pos = _self.object:get_pos()
|
||||
timer = timer - _self.dtime
|
||||
if timer <= 0
|
||||
or _self:pos_in_box({x = pos2.x, y = pos.y + 0.1, z = pos2.z}) then
|
||||
_self:halt()
|
||||
return true
|
||||
end
|
||||
_self:move(pos2, method or "creatura:neighbors", speed_factor or 0.5, anim)
|
||||
move_init = true
|
||||
end
|
||||
self:set_action(func)
|
||||
end
|
||||
|
||||
function creatura.action_fly(self, pos2, timeout, method, speed_factor, anim)
|
||||
local timer = timeout or 4
|
||||
local move_init = false
|
||||
local function func(self)
|
||||
if not pos2
|
||||
or (move_init
|
||||
and not self._movement_data.goal) then return true end
|
||||
local pos = self.object:get_pos()
|
||||
timer = timer - self.dtime
|
||||
if timer <= 0
|
||||
or self:pos_in_box(pos2) then
|
||||
self:halt()
|
||||
return true
|
||||
end
|
||||
self:move(pos2, method, speed_factor or 0.5, anim)
|
||||
move_init = true
|
||||
end
|
||||
self:set_action(func)
|
||||
local timer = timeout or 4
|
||||
local move_init = false
|
||||
local function func(_self)
|
||||
if not pos2
|
||||
or (move_init
|
||||
and not _self._movement_data.goal) then return true end
|
||||
timer = timer - _self.dtime
|
||||
if timer <= 0
|
||||
or _self:pos_in_box(pos2) then
|
||||
_self:halt()
|
||||
return true
|
||||
end
|
||||
_self:move(pos2, method, speed_factor or 0.5, anim)
|
||||
move_init = true
|
||||
end
|
||||
self:set_action(func)
|
||||
end
|
||||
|
||||
-- Idle
|
||||
|
||||
function creatura.action_idle(self, time, anim)
|
||||
local timer = time
|
||||
local function func(self)
|
||||
self:set_gravity(-9.8)
|
||||
self:halt()
|
||||
self:animate(anim or "stand")
|
||||
timer = timer - self.dtime
|
||||
if timer <= 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
self:set_action(func)
|
||||
local timer = time
|
||||
local function func(_self)
|
||||
_self:set_gravity(-9.8)
|
||||
_self:halt()
|
||||
_self:animate(anim or "stand")
|
||||
timer = timer - _self.dtime
|
||||
if timer <= 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
self:set_action(func)
|
||||
end
|
||||
|
||||
-- Rotate on Z axis in random direction until 90 degree angle is reached
|
||||
|
@ -154,22 +148,22 @@ end
|
|||
function creatura.action_fallover(self)
|
||||
local zrot = 0
|
||||
local init = false
|
||||
local dir = 1
|
||||
local function func(self)
|
||||
local dir = 1
|
||||
local function func(_self)
|
||||
if not init then
|
||||
self:animate("stand")
|
||||
if random(2) < 2 then
|
||||
dir = -1
|
||||
end
|
||||
_self:animate("stand")
|
||||
if random(2) < 2 then
|
||||
dir = -1
|
||||
end
|
||||
init = true
|
||||
end
|
||||
local rot = self.object:get_rotation()
|
||||
local goal = (pi * 0.5) * dir
|
||||
local dif = abs(rot.z - goal)
|
||||
zrot = rot.z + (dif * dir) * 0.15
|
||||
self.object:set_rotation({x = rot.x, y = rot.y, z = zrot})
|
||||
local rot = _self.object:get_rotation()
|
||||
local goal = (pi * 0.5) * dir
|
||||
local dif = abs(rot.z - goal)
|
||||
zrot = rot.z + (dif * dir) * 0.15
|
||||
_self.object:set_rotation({x = rot.x, y = rot.y, z = zrot})
|
||||
if (dir > 0 and zrot >= goal)
|
||||
or (dir < 0 and zrot <= goal) then return true end
|
||||
or (dir < 0 and zrot <= goal) then return true end
|
||||
end
|
||||
self:set_action(func)
|
||||
end
|
||||
|
@ -181,210 +175,208 @@ end
|
|||
-- Pathfinding
|
||||
|
||||
creatura.register_movement_method("creatura:pathfind", function(self, pos2)
|
||||
-- Movement Data
|
||||
local pos = self.object:get_pos()
|
||||
local movement_data = self._movement_data
|
||||
local waypoint = movement_data.waypoint
|
||||
local speed = movement_data.speed or 5
|
||||
local path = self._path
|
||||
if not path or #path < 2 then
|
||||
if get_collision(self, dir2yaw(vec_dir(pos, pos2))) then
|
||||
self._path = creatura.find_path(self, pos, pos2, self.width, self.height, 200) or {}
|
||||
end
|
||||
else
|
||||
waypoint = self._path[2]
|
||||
if self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}) then
|
||||
-- Waypoint Y axis is raised to avoid large mobs spinning over downward slopes
|
||||
table.remove(self._path, 1)
|
||||
end
|
||||
end
|
||||
if not waypoint
|
||||
or self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}) then
|
||||
waypoint = creatura.get_next_move(self, pos2)
|
||||
self._movement_data.waypoint = waypoint
|
||||
end
|
||||
-- Turning
|
||||
local dir2waypoint = vec_dir(pos, pos2)
|
||||
if waypoint then
|
||||
dir2waypoint = vec_dir(pos, waypoint)
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
local tgt_yaw = dir2yaw(dir2waypoint)
|
||||
local turn_rate = abs(self.turn_rate or 5)
|
||||
local yaw_diff = abs(diff(yaw, tgt_yaw))
|
||||
-- Moving
|
||||
self:set_gravity(-9.8)
|
||||
if yaw_diff < pi * (turn_rate * 0.1) then
|
||||
self:set_forward_velocity(speed)
|
||||
else
|
||||
self:set_forward_velocity(speed * 0.5)
|
||||
turn_rate = turn_rate * 1.5
|
||||
end
|
||||
self:animate(movement_data.anim or "walk")
|
||||
self:turn_to(tgt_yaw, turn_rate)
|
||||
if self:pos_in_box(pos2)
|
||||
or (waypoint
|
||||
and not self:is_pos_safe(waypoint)) then
|
||||
self:halt()
|
||||
end
|
||||
-- Movement Data
|
||||
local pos = self.object:get_pos()
|
||||
local movement_data = self._movement_data
|
||||
local waypoint = movement_data.waypoint
|
||||
local speed = movement_data.speed or 5
|
||||
local path = self._path
|
||||
if not path or #path < 2 then
|
||||
if get_collision(self, dir2yaw(vec_dir(pos, pos2))) then
|
||||
self._path = creatura.find_path(self, pos, pos2, self.width, self.height, 200) or {}
|
||||
end
|
||||
else
|
||||
waypoint = self._path[2]
|
||||
if self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}) then
|
||||
-- Waypoint Y axis is raised to avoid large mobs spinning over downward slopes
|
||||
table.remove(self._path, 1)
|
||||
end
|
||||
end
|
||||
if not waypoint
|
||||
or self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}) then
|
||||
waypoint = creatura.get_next_move(self, pos2)
|
||||
self._movement_data.waypoint = waypoint
|
||||
end
|
||||
-- Turning
|
||||
local dir2waypoint = vec_dir(pos, pos2)
|
||||
if waypoint then
|
||||
dir2waypoint = vec_dir(pos, waypoint)
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
local tgt_yaw = dir2yaw(dir2waypoint)
|
||||
local turn_rate = abs(self.turn_rate or 5)
|
||||
local yaw_diff = abs(diff(yaw, tgt_yaw))
|
||||
-- Moving
|
||||
self:set_gravity(-9.8)
|
||||
if yaw_diff < pi * (turn_rate * 0.1) then
|
||||
self:set_forward_velocity(speed)
|
||||
else
|
||||
self:set_forward_velocity(speed * 0.5)
|
||||
turn_rate = turn_rate * 1.5
|
||||
end
|
||||
self:animate(movement_data.anim or "walk")
|
||||
self:turn_to(tgt_yaw, turn_rate)
|
||||
if self:pos_in_box(pos2)
|
||||
or (waypoint
|
||||
and not self:is_pos_safe(waypoint)) then
|
||||
self:halt()
|
||||
end
|
||||
end)
|
||||
|
||||
creatura.register_movement_method("creatura:theta_pathfind", function(self, pos2)
|
||||
-- Movement Data
|
||||
local pos = self.object:get_pos()
|
||||
local movement_data = self._movement_data
|
||||
local waypoint = movement_data.waypoint
|
||||
local speed = movement_data.speed or 5
|
||||
local path = self._path
|
||||
if not path or #path < 1 then
|
||||
self._path = creatura.find_theta_path(self, pos, pos2, self.width, self.height, 300) or {}
|
||||
else
|
||||
waypoint = self._path[2] or self._path[1]
|
||||
if self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}) then
|
||||
-- Waypoint Y axis is raised to avoid large mobs spinning over downward slopes
|
||||
table.remove(self._path, 1)
|
||||
end
|
||||
end
|
||||
if not waypoint
|
||||
or self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}) then
|
||||
waypoint = creatura.get_next_move(self, pos2)
|
||||
self._movement_data.waypoint = waypoint
|
||||
end
|
||||
-- Turning
|
||||
local dir2waypoint = vec_dir(pos, pos2)
|
||||
if waypoint then
|
||||
dir2waypoint = vec_dir(pos, waypoint)
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
local tgt_yaw = dir2yaw(dir2waypoint)
|
||||
local turn_rate = abs(self.turn_rate or 5)
|
||||
local yaw_diff = abs(diff(yaw, tgt_yaw))
|
||||
-- Moving
|
||||
self:set_gravity(-9.8)
|
||||
if yaw_diff < pi * (turn_rate * 0.1) then
|
||||
self:set_forward_velocity(speed)
|
||||
else
|
||||
self:set_forward_velocity(speed * 0.5)
|
||||
turn_rate = turn_rate * 1.5
|
||||
end
|
||||
self:animate(movement_data.anim or "walk")
|
||||
self:turn_to(tgt_yaw, turn_rate)
|
||||
if self:pos_in_box(pos2)
|
||||
or (waypoint
|
||||
and not self:is_pos_safe(waypoint)) then
|
||||
self:halt()
|
||||
end
|
||||
-- Movement Data
|
||||
local pos = self.object:get_pos()
|
||||
local movement_data = self._movement_data
|
||||
local waypoint = movement_data.waypoint
|
||||
local speed = movement_data.speed or 5
|
||||
local path = self._path
|
||||
if not path or #path < 1 then
|
||||
self._path = creatura.find_theta_path(self, pos, pos2, self.width, self.height, 300) or {}
|
||||
else
|
||||
waypoint = self._path[2] or self._path[1]
|
||||
if self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}) then
|
||||
-- Waypoint Y axis is raised to avoid large mobs spinning over downward slopes
|
||||
table.remove(self._path, 1)
|
||||
end
|
||||
end
|
||||
if not waypoint
|
||||
or self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}) then
|
||||
waypoint = creatura.get_next_move(self, pos2)
|
||||
self._movement_data.waypoint = waypoint
|
||||
end
|
||||
-- Turning
|
||||
local dir2waypoint = vec_dir(pos, pos2)
|
||||
if waypoint then
|
||||
dir2waypoint = vec_dir(pos, waypoint)
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
local tgt_yaw = dir2yaw(dir2waypoint)
|
||||
local turn_rate = abs(self.turn_rate or 5)
|
||||
local yaw_diff = abs(diff(yaw, tgt_yaw))
|
||||
-- Moving
|
||||
self:set_gravity(-9.8)
|
||||
if yaw_diff < pi * (turn_rate * 0.1) then
|
||||
self:set_forward_velocity(speed)
|
||||
else
|
||||
self:set_forward_velocity(speed * 0.5)
|
||||
turn_rate = turn_rate * 1.5
|
||||
end
|
||||
self:animate(movement_data.anim or "walk")
|
||||
self:turn_to(tgt_yaw, turn_rate)
|
||||
if self:pos_in_box(pos2)
|
||||
or (waypoint
|
||||
and not self:is_pos_safe(waypoint)) then
|
||||
self:halt()
|
||||
end
|
||||
end)
|
||||
|
||||
-- Neighbors
|
||||
|
||||
creatura.register_movement_method("creatura:neighbors", function(self, pos2)
|
||||
-- Movement Data
|
||||
local pos = self.object:get_pos()
|
||||
local movement_data = self._movement_data
|
||||
local waypoint = movement_data.waypoint
|
||||
local speed = movement_data.speed or 5
|
||||
if not waypoint
|
||||
or self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}, clamp(self.width, 0.5, 1)) then
|
||||
-- Waypoint Y axis is raised to avoid large mobs spinning over downward slopes
|
||||
waypoint = creatura.get_next_move(self, pos2)
|
||||
self._movement_data.waypoint = waypoint
|
||||
end
|
||||
-- Turning
|
||||
local dir2waypoint = vec_dir(pos, pos2)
|
||||
if waypoint then
|
||||
dir2waypoint = vec_dir(pos, waypoint)
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
local tgt_yaw = dir2yaw(dir2waypoint)
|
||||
local turn_rate = abs(self.turn_rate or 5)
|
||||
local yaw_diff = abs(diff(yaw, tgt_yaw))
|
||||
-- Moving
|
||||
self:set_gravity(-9.8)
|
||||
if yaw_diff < pi * 0.25 then
|
||||
self:set_forward_velocity(speed)
|
||||
else
|
||||
self:set_forward_velocity(speed * 0.5)
|
||||
turn_rate = turn_rate * 1.5
|
||||
end
|
||||
self:animate(movement_data.anim or "walk")
|
||||
self:turn_to(tgt_yaw, turn_rate)
|
||||
if self:pos_in_box(pos2)
|
||||
or (waypoint
|
||||
and not self:is_pos_safe(waypoint)) then
|
||||
self:halt()
|
||||
end
|
||||
-- Movement Data
|
||||
local pos = self.object:get_pos()
|
||||
local movement_data = self._movement_data
|
||||
local waypoint = movement_data.waypoint
|
||||
local speed = movement_data.speed or 5
|
||||
if not waypoint
|
||||
or self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}, clamp(self.width, 0.5, 1)) then
|
||||
-- Waypoint Y axis is raised to avoid large mobs spinning over downward slopes
|
||||
waypoint = creatura.get_next_move(self, pos2)
|
||||
self._movement_data.waypoint = waypoint
|
||||
end
|
||||
-- Turning
|
||||
local dir2waypoint = vec_dir(pos, pos2)
|
||||
if waypoint then
|
||||
dir2waypoint = vec_dir(pos, waypoint)
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
local tgt_yaw = dir2yaw(dir2waypoint)
|
||||
local turn_rate = abs(self.turn_rate or 5)
|
||||
local yaw_diff = abs(diff(yaw, tgt_yaw))
|
||||
-- Moving
|
||||
self:set_gravity(-9.8)
|
||||
if yaw_diff < pi * 0.25 then
|
||||
self:set_forward_velocity(speed)
|
||||
else
|
||||
self:set_forward_velocity(speed * 0.5)
|
||||
turn_rate = turn_rate * 1.5
|
||||
end
|
||||
self:animate(movement_data.anim or "walk")
|
||||
self:turn_to(tgt_yaw, turn_rate)
|
||||
if self:pos_in_box(pos2)
|
||||
or (waypoint
|
||||
and not self:is_pos_safe(waypoint)) then
|
||||
self:halt()
|
||||
end
|
||||
end)
|
||||
|
||||
-- Obstacle Avoidance
|
||||
|
||||
local function get_obstacle_avoidance(self, goal)
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
local pos = self.object:get_pos()
|
||||
pos.y = pos.y + 1
|
||||
local yaw2goal = dir2yaw(vec_dir(pos, goal))
|
||||
local outset = vec_add(pos, vec_multi(yaw2dir(yaw2goal), width))
|
||||
local collide, col_pos = get_collision(self, yaw2goal)
|
||||
local avd_pos
|
||||
if collide then
|
||||
for i = 45, 180, 45 do
|
||||
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
|
||||
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
|
||||
end
|
||||
return avd_pos
|
||||
local width = self.width
|
||||
local height = self.height
|
||||
local pos = self.object:get_pos()
|
||||
pos.y = pos.y + 1
|
||||
local yaw2goal = dir2yaw(vec_dir(pos, goal))
|
||||
local collide, col_pos = get_collision(self, yaw2goal)
|
||||
if not collide then return end
|
||||
local avd_pos
|
||||
for i = 45, 180, 45 do
|
||||
local angle = rad(i)
|
||||
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
|
||||
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
|
||||
|
||||
creatura.register_movement_method("creatura:obstacle_avoidance", function(self, pos2)
|
||||
-- Movement Data
|
||||
local pos = self.object:get_pos()
|
||||
local movement_data = self._movement_data
|
||||
local waypoint = movement_data.waypoint
|
||||
local speed = movement_data.speed or 5
|
||||
if not waypoint
|
||||
or self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}, clamp(self.width, 0.5, 1)) then
|
||||
-- Waypoint Y axis is raised to avoid large mobs spinning over downward slopes
|
||||
waypoint = get_obstacle_avoidance(self, pos2)
|
||||
self._movement_data.waypoint = waypoint
|
||||
end
|
||||
-- Turning
|
||||
local dir2waypoint = vec_dir(pos, pos2)
|
||||
if waypoint then
|
||||
dir2waypoint = vec_dir(pos, waypoint)
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
local tgt_yaw = dir2yaw(dir2waypoint)
|
||||
local turn_rate = abs(self.turn_rate or 5)
|
||||
local yaw_diff = abs(diff(yaw, tgt_yaw))
|
||||
-- Moving
|
||||
self:set_gravity(-9.8)
|
||||
if yaw_diff < pi * 0.25 then
|
||||
self:set_forward_velocity(speed)
|
||||
else
|
||||
self:set_forward_velocity(speed * 0.5)
|
||||
turn_rate = turn_rate * 1.5
|
||||
end
|
||||
self:animate(movement_data.anim or "walk")
|
||||
self:turn_to(tgt_yaw, turn_rate)
|
||||
if self:pos_in_box(pos2)
|
||||
or (waypoint
|
||||
and not self:is_pos_safe(waypoint)) then
|
||||
self:halt()
|
||||
end
|
||||
-- Movement Data
|
||||
local pos = self.object:get_pos()
|
||||
local movement_data = self._movement_data
|
||||
local waypoint = movement_data.waypoint
|
||||
local speed = movement_data.speed or 5
|
||||
if not waypoint
|
||||
or self:pos_in_box({x = waypoint.x, y = pos.y + self.height * 0.5, z = waypoint.z}, clamp(self.width, 0.5, 1)) then
|
||||
-- Waypoint Y axis is raised to avoid large mobs spinning over downward slopes
|
||||
waypoint = get_obstacle_avoidance(self, pos2)
|
||||
self._movement_data.waypoint = waypoint
|
||||
end
|
||||
-- Turning
|
||||
local dir2waypoint = vec_dir(pos, pos2)
|
||||
if waypoint then
|
||||
dir2waypoint = vec_dir(pos, waypoint)
|
||||
end
|
||||
local yaw = self.object:get_yaw()
|
||||
local tgt_yaw = dir2yaw(dir2waypoint)
|
||||
local turn_rate = abs(self.turn_rate or 5)
|
||||
local yaw_diff = abs(diff(yaw, tgt_yaw))
|
||||
-- Moving
|
||||
self:set_gravity(-9.8)
|
||||
if yaw_diff < pi * 0.25 then
|
||||
self:set_forward_velocity(speed)
|
||||
else
|
||||
self:set_forward_velocity(speed * 0.5)
|
||||
turn_rate = turn_rate * 1.5
|
||||
end
|
||||
self:animate(movement_data.anim or "walk")
|
||||
self:turn_to(tgt_yaw, turn_rate)
|
||||
if self:pos_in_box(pos2)
|
||||
or (waypoint
|
||||
and not self:is_pos_safe(waypoint)) then
|
||||
self:halt()
|
||||
end
|
||||
end)
|
181
mob_meta.lua
181
mob_meta.lua
|
@ -15,12 +15,7 @@ local cos = math.cos
|
|||
local atan2 = math.atan2
|
||||
|
||||
local function diff(a, b) -- Get difference between 2 angles
|
||||
return math.atan2(math.sin(b - a), math.cos(b - a))
|
||||
end
|
||||
|
||||
local function round(n, dec)
|
||||
local x = 10^(dec or 0)
|
||||
return math.floor(n * x + 0.5) / x
|
||||
return atan2(sin(b - a), cos(b - a))
|
||||
end
|
||||
|
||||
local vec_dir = vector.direction
|
||||
|
@ -50,89 +45,13 @@ end
|
|||
|
||||
-- Local Utilities --
|
||||
|
||||
local default_node_def = {walkable = true} -- both ignore and unknown nodes are walkable
|
||||
|
||||
local function get_node_height(name)
|
||||
local def = minetest.registered_nodes[name]
|
||||
if not def then return 0.5 end
|
||||
if def.walkable then
|
||||
if def.drawtype == "nodebox" then
|
||||
if def.node_box
|
||||
and def.node_box.type == "fixed" then
|
||||
if type(def.node_box.fixed[1]) == "number" then
|
||||
return 0.5 + def.node_box.fixed[5]
|
||||
elseif type(def.node_box.fixed[1]) == "table" then
|
||||
return 0.5 + def.node_box.fixed[1][5]
|
||||
else
|
||||
return 1
|
||||
end
|
||||
else
|
||||
return 1
|
||||
end
|
||||
else
|
||||
return 1
|
||||
end
|
||||
else
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
local function get_node_def(name)
|
||||
local def = minetest.registered_nodes[name] or default_node_def
|
||||
if def.walkable
|
||||
and get_node_height(name) < 0.26 then
|
||||
def.walkable = false -- workaround for nodes like snow
|
||||
end
|
||||
return def
|
||||
end
|
||||
|
||||
local function get_ground_level(pos2, max_diff)
|
||||
local node = minetest.get_node(pos2)
|
||||
local node_under = minetest.get_node({
|
||||
x = pos2.x,
|
||||
y = pos2.y - 1,
|
||||
z = pos2.z
|
||||
})
|
||||
local walkable = get_node_def(node_under.name) and not get_node_def(node.name)
|
||||
if walkable then
|
||||
return pos2
|
||||
end
|
||||
local diff = 0
|
||||
if not get_node_def(node_under.name) then
|
||||
for i = 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 = get_node_def(node_under.name) and not get_node_def(node.name)
|
||||
if walkable then break end
|
||||
end
|
||||
else
|
||||
for i = 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 = get_node_def(node_under.name) and not get_node_def(node.name)
|
||||
if walkable then break end
|
||||
end
|
||||
end
|
||||
return pos2
|
||||
end
|
||||
|
||||
local function is_value_in_table(tbl, val)
|
||||
for _, v in pairs(tbl) do
|
||||
if v == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
for _, v in pairs(tbl) do
|
||||
if v == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------
|
||||
|
@ -204,7 +123,7 @@ end
|
|||
function mob:indicate_damage()
|
||||
self._original_texture_mod = self._original_texture_mod or self.object:get_texture_mod()
|
||||
self.object:set_texture_mod(self._original_texture_mod .. "^[colorize:#FF000040")
|
||||
core.after(0.2, function()
|
||||
minetest.after(0.2, function()
|
||||
if creatura.is_alive(self) then
|
||||
self.object:set_texture_mod(self._original_texture_mod)
|
||||
end
|
||||
|
@ -265,8 +184,8 @@ end
|
|||
|
||||
-- Sets Velocity to desired speed in mobs current look direction
|
||||
|
||||
function mob:set_forward_velocity(speed)
|
||||
local speed = speed or self._movement_data.speed
|
||||
function mob:set_forward_velocity(_speed)
|
||||
local speed = _speed or self._movement_data.speed
|
||||
local dir = minetest.yaw_to_dir(self.object:get_yaw())
|
||||
local vel = vec_multi(dir, speed)
|
||||
vel.y = self.object:get_velocity().y
|
||||
|
@ -367,12 +286,11 @@ end
|
|||
function mob:get_wander_pos(min_range, max_range, dir)
|
||||
local pos = vec_center(self.object:get_pos())
|
||||
pos.y = floor(pos.y + 0.5)
|
||||
local node = minetest.get_node(pos)
|
||||
if get_node_def(node.name).walkable then -- Occurs if small mob is touching a fence
|
||||
if creatura.get_node_def(pos).walkable then -- Occurs if small mob is touching a fence
|
||||
local offset = vector.add(pos, vec_multi(vec_dir(pos, self.object:get_pos()), 1.5))
|
||||
pos.x = floor(offset.x + 0.5)
|
||||
pos.z = floor(offset.z + 0.5)
|
||||
pos = get_ground_level(pos, 1)
|
||||
pos = creatura.get_ground_level(pos, 1)
|
||||
end
|
||||
local width = self.width
|
||||
local outset = random(min_range, max_range)
|
||||
|
@ -383,16 +301,16 @@ function mob:get_wander_pos(min_range, max_range, dir)
|
|||
z = random(-10, 10) * 0.1
|
||||
})
|
||||
local pos2 = vec_add(pos, vec_multi(move_dir, width))
|
||||
if get_node_def(minetest.get_node(pos2).name).walkable
|
||||
if creatura.get_node_def(pos2).walkable
|
||||
and not dir then
|
||||
for i = 1, 3 do
|
||||
for _ = 1, 3 do
|
||||
move_dir = {
|
||||
x = move_dir.z,
|
||||
y = 0,
|
||||
z = move_dir.x * -1
|
||||
}
|
||||
pos2 = vec_add(pos, vec_multi(move_dir, width))
|
||||
if not get_node_def(minetest.get_node(pos2).name).walkable then
|
||||
if not creatura.get_node_def(pos2).walkable then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -401,14 +319,12 @@ function mob:get_wander_pos(min_range, max_range, dir)
|
|||
end
|
||||
for i = 1, outset do
|
||||
local a_pos = vec_add(pos2, vec_multi(move_dir, i))
|
||||
local a_node = minetest.get_node(a_pos)
|
||||
local b_pos = {x = a_pos.x, y = a_pos.y - 1, z = a_pos.z}
|
||||
local b_node = minetest.get_node(b_pos)
|
||||
if get_node_def(a_node.name).walkable
|
||||
or not get_node_def(b_node.name).walkable then
|
||||
a_pos = get_ground_level(a_pos, floor(self.stepheight or 1))
|
||||
if creatura.get_node_def(a_pos).walkable
|
||||
or not creatura.get_node_def(b_pos).walkable then
|
||||
a_pos = creatura.get_ground_level(a_pos, floor(self.stepheight or 1))
|
||||
end
|
||||
if not get_node_def(a_node.name).walkable then
|
||||
if not creatura.get_node_def(a_pos).walkable then
|
||||
pos2 = a_pos
|
||||
else
|
||||
break
|
||||
|
@ -419,12 +335,11 @@ end
|
|||
|
||||
function mob:get_wander_pos_3d(min_range, max_range, dir, vert_bias)
|
||||
local pos = vec_center(self.object:get_pos())
|
||||
local node = minetest.get_node(pos)
|
||||
if get_node_def(node.name).walkable then -- Occurs if small mob is touching a fence
|
||||
if creatura.get_node_def(pos).walkable then -- Occurs if small mob is touching a fence
|
||||
local offset = vector.add(pos, vec_multi(vec_dir(pos, self.object:get_pos()), 1.5))
|
||||
pos.x = floor(offset.x + 0.5)
|
||||
pos.z = floor(offset.z + 0.5)
|
||||
pos = get_ground_level(pos, 1)
|
||||
pos = creatura.get_ground_level(pos, 1)
|
||||
end
|
||||
local width = self.width
|
||||
local outset = random(min_range, max_range)
|
||||
|
@ -435,16 +350,16 @@ function mob:get_wander_pos_3d(min_range, max_range, dir, vert_bias)
|
|||
z = random(-10, 10) * 0.1
|
||||
})
|
||||
local pos2 = vec_add(pos, vec_multi(move_dir, width))
|
||||
if get_node_def(minetest.get_node(pos2).name).walkable
|
||||
if creatura.get_node_def(pos2).walkable
|
||||
and not dir then
|
||||
for i = 1, 3 do
|
||||
for _ = 1, 3 do
|
||||
move_dir = {
|
||||
x = move_dir.z,
|
||||
y = move_dir.y,
|
||||
z = move_dir.x * -1
|
||||
}
|
||||
pos2 = vec_add(pos, vec_multi(move_dir, width))
|
||||
if not get_node_def(minetest.get_node(pos2).name).walkable then
|
||||
if not creatura.get_node_def(pos2).walkable then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -453,11 +368,10 @@ function mob:get_wander_pos_3d(min_range, max_range, dir, vert_bias)
|
|||
end
|
||||
for i = 1, outset do
|
||||
local a_pos = vec_add(pos2, vec_multi(move_dir, i))
|
||||
local a_node = minetest.get_node(a_pos)
|
||||
if get_node_def(a_node.name).walkable then
|
||||
a_pos = get_ground_level(a_pos, floor(self.stepheight or 1))
|
||||
if creatura.get_node_def(a_pos).walkable then
|
||||
a_pos = creatura.get_ground_level(a_pos, floor(self.stepheight or 1))
|
||||
end
|
||||
if not get_node_def(a_node.name).walkable then
|
||||
if not creatura.get_node_def(a_pos).walkable then
|
||||
pos2 = a_pos
|
||||
else
|
||||
break
|
||||
|
@ -471,8 +385,8 @@ function mob:is_pos_safe(pos)
|
|||
local node = minetest.get_node(pos)
|
||||
if not node then return false end
|
||||
if minetest.get_item_group(node.name, "igniter") > 0
|
||||
or get_node_def(node.name).drawtype == "liquid"
|
||||
or get_node_def(minetest.get_node(vec_raise(pos, -1)).name).drawtype == "liquid" then return false end
|
||||
or creatura.get_node_def(node.name).drawtype == "liquid"
|
||||
or creatura.get_node_def(vec_raise(pos, -1)).drawtype == "liquid" then return false end
|
||||
local fall_safe = false
|
||||
if self.max_fall ~= 0 then
|
||||
for i = 1, self.max_fall or 3 do
|
||||
|
@ -481,7 +395,7 @@ function mob:is_pos_safe(pos)
|
|||
y = floor(mob_pos.y + 0.5) - i,
|
||||
z = pos.z
|
||||
}
|
||||
if get_node_def(minetest.get_node(fall_pos).name).walkable then
|
||||
if creatura.get_node_def(fall_pos).walkable then
|
||||
fall_safe = true
|
||||
break
|
||||
end
|
||||
|
@ -809,9 +723,9 @@ function mob:activate(staticdata, dtime)
|
|||
|
||||
if self.timer
|
||||
and type(self.timer) == "number" then -- fix crash for converted mobs_redo mobs
|
||||
self.timer = function(self, n)
|
||||
local t1 = floor(self.active_time)
|
||||
local t2 = floor(self.active_time + self.dtime)
|
||||
self.timer = function(_self, n)
|
||||
local t1 = floor(_self.active_time)
|
||||
local t2 = floor(_self.active_time + _self.dtime)
|
||||
if t2 > t1 and t2%n == 0 then return true end
|
||||
end
|
||||
end
|
||||
|
@ -830,7 +744,6 @@ function mob:staticdata()
|
|||
end
|
||||
|
||||
function mob:on_step(dtime, moveresult)
|
||||
--local us_time = minetest.get_us_time()
|
||||
if not self.hp then return end
|
||||
self.dtime = dtime or 0.09
|
||||
self.moveresult = moveresult or {}
|
||||
|
@ -851,11 +764,12 @@ function mob:on_step(dtime, moveresult)
|
|||
self.width = self:get_hitbox()[4] or 0.5
|
||||
self.height = self:get_height() or 1
|
||||
end
|
||||
self:_light_physics()
|
||||
--local us_time = minetest.get_us_time()
|
||||
-- Movement Control
|
||||
if self._move then
|
||||
self:_move()
|
||||
end
|
||||
--minetest.chat_send_all(minetest.get_us_time() - us_time)
|
||||
if self.utility_stack
|
||||
and self._execute_utilities then
|
||||
self:_execute_utilities()
|
||||
|
@ -912,7 +826,9 @@ local function do_step(self)
|
|||
and abs(vel.x + vel.z) > 0 then
|
||||
local border = self._border
|
||||
local yaw_offset = vec_add(pos, vec_multi(minetest.yaw_to_dir(self.object:get_yaw()), self.width + 0.7))
|
||||
table.sort(border, function(a, b) return vec_dist(vec_add(pos, a), yaw_offset) < vec_dist(vec_add(pos, b), yaw_offset) end)
|
||||
table.sort(border, function(a, b)
|
||||
return vec_dist(vec_add(pos, a), yaw_offset) < vec_dist(vec_add(pos, b), yaw_offset)
|
||||
end)
|
||||
local step_pos = vec_center(vec_add(pos, border[1]))
|
||||
local halfway = vec_add(pos, vec_multi(vec_dir(pos, step_pos), 0.5))
|
||||
halfway.y = step_pos.y
|
||||
|
@ -923,7 +839,6 @@ local function do_step(self)
|
|||
end
|
||||
end
|
||||
else
|
||||
local vel = self.object:get_velocity()
|
||||
self.object:set_velocity(vector.new(vel.x, 7, vel.z))
|
||||
if self._step.y < pos.y - 0.5 then
|
||||
self.object:set_velocity(vector.new(vel.x, 0.5, vel.z))
|
||||
|
@ -943,7 +858,6 @@ local function collision_detection(self)
|
|||
local width = self.width + 0.25
|
||||
local objects = minetest.get_objects_in_area(vec_sub(pos, width), vec_add(pos, width))
|
||||
if #objects < 2 then return end
|
||||
local col_no = 0
|
||||
for i = 2, #objects do
|
||||
local object = objects[i]
|
||||
if creatura.is_alive(object)
|
||||
|
@ -975,7 +889,6 @@ local function water_physics(self)
|
|||
floor_pos.y = floor_pos.y + 0.01
|
||||
local surface_pos = floor_pos
|
||||
local floor_node = minetest.get_node(floor_pos)
|
||||
local surface_node = minetest.get_node(surface_pos)
|
||||
if minetest.get_item_group(floor_node.name, "liquid") < 1 then
|
||||
self.object:set_acceleration({
|
||||
x = 0,
|
||||
|
@ -1012,7 +925,7 @@ local function water_physics(self)
|
|||
})
|
||||
local hydrodynamics = self.hydrodynamics_multiplier or 0.7
|
||||
local vel_y = vel.y
|
||||
if self.bouyancy_multiplier == 0 then -- if bouyancy is disabled drag will be applied to keep awuatic mobs from drifting
|
||||
if self.bouyancy_multiplier == 0 then
|
||||
vel_y = vel.y * hydrodynamics
|
||||
end
|
||||
self.object:set_velocity({
|
||||
|
@ -1084,7 +997,6 @@ end
|
|||
|
||||
function mob:_execute_actions()
|
||||
if not self.object then return end
|
||||
local task = self._task
|
||||
if #self._task > 0 then
|
||||
local func = self._task[#self._task].func
|
||||
if func(self) then
|
||||
|
@ -1128,7 +1040,7 @@ function mob:_execute_utilities()
|
|||
func = nil,
|
||||
score = 0
|
||||
}
|
||||
if (self:timer(self.task_timer or 1)
|
||||
if (self:timer(self.util_timer or 1)
|
||||
or not self._utility_data.func)
|
||||
and is_alive then
|
||||
for i = 1, #self.utility_stack do
|
||||
|
@ -1163,7 +1075,8 @@ function mob:_execute_utilities()
|
|||
self._utility_data = loop_data
|
||||
else
|
||||
local no_data = not self._utility_data.utility and not self._utility_data.args
|
||||
local new_util = self._utility_data.utility ~= loop_data.utility or not tbl_equals(self._utility_data.args, loop_data.args)
|
||||
local same_args = tbl_equals(self._utility_data.args, loop_data.args)
|
||||
local new_util = self._utility_data.utility ~= loop_data.utility or not same_args
|
||||
if no_data
|
||||
or new_util then -- if utilities are different or utilities are the same and args are different set new data
|
||||
self._utility_data = loop_data
|
||||
|
@ -1218,9 +1131,10 @@ function mob:_vitals()
|
|||
end
|
||||
if self:timer(1) then
|
||||
local head_pos = vec_raise(stand_pos, self.height)
|
||||
local head_def = get_node_def(minetest.get_node(head_pos).name)
|
||||
local head_node = minetest.get_node(head_pos)
|
||||
local head_def = creatura.get_node_def(head_node.name)
|
||||
if head_def.drawtype == "liquid"
|
||||
and minetest.get_item_group(minetest.get_node(head_pos).name, "water") > 0 then
|
||||
and minetest.get_item_group(head_node.name, "water") > 0 then
|
||||
if self._breath <= 0 then
|
||||
self:hurt(1)
|
||||
self:indicate_damage()
|
||||
|
@ -1232,8 +1146,9 @@ function mob:_vitals()
|
|||
self:memorize("_breath", self._breath)
|
||||
end
|
||||
end
|
||||
local stand_def = get_node_def(minetest.get_node(stand_pos).name)
|
||||
if minetest.get_item_group(minetest.get_node(stand_pos).name, "fire") > 0
|
||||
local stand_node = minetest.get_node(stand_pos)
|
||||
local stand_def = creatura.get_node_def(stand_node.name)
|
||||
if minetest.get_item_group(stand_node.name, "fire") > 0
|
||||
and stand_def.damage_per_second then
|
||||
local damage = stand_def.damage_per_second
|
||||
local resist = self.fire_resistance or 0.5
|
||||
|
|
1001
pathfinder.lua
1001
pathfinder.lua
File diff suppressed because it is too large
Load diff
|
@ -350,4 +350,4 @@ minetest.register_abm({
|
|||
end
|
||||
end
|
||||
end,
|
||||
})]]
|
||||
})]]
|
Loading…
Add table
Reference in a new issue