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