Add stuff?
parent
b7556f6e28
commit
27f7336ad7
|
@ -28,6 +28,18 @@ director.spawn_list = {
|
|||
spawn_time = 31.0,
|
||||
spawn_location = "ground",
|
||||
},
|
||||
{
|
||||
description = "Aranay group",
|
||||
name = "defense:aranay",
|
||||
intensity_min = 0.0,
|
||||
intensity_max = 0.5,
|
||||
group_min = 1,
|
||||
group_max = 2,
|
||||
probability = 0.3,
|
||||
day_start = 0,
|
||||
spawn_time = 18.0,
|
||||
spawn_location = "ground",
|
||||
},
|
||||
{
|
||||
description = "Paniki group",
|
||||
name = "defense:paniki",
|
||||
|
@ -274,9 +286,11 @@ function director:load()
|
|||
if data then
|
||||
self.intensity = data.intensity
|
||||
self.cooldown_timer = data.cooldown_timer
|
||||
spawn_timers = data.spawn_timers
|
||||
last_average_health = data.last_average_health
|
||||
last_mob_count = data.last_mob_count
|
||||
for k,v in pairs(data.spawn_timers) do
|
||||
spawn_timers[k] = v
|
||||
end
|
||||
end
|
||||
assert(file:close())
|
||||
end
|
||||
|
|
|
@ -37,6 +37,7 @@ dofile2("music.lua")
|
|||
|
||||
dofile2("mob.lua")
|
||||
dofile2("mobs/unggoy.lua")
|
||||
dofile2("mobs/aranay.lua")
|
||||
dofile2("mobs/sarangay.lua")
|
||||
dofile2("mobs/paniki.lua")
|
||||
dofile2("mobs/botete.lua")
|
|
@ -7,7 +7,7 @@ mobs.default_prototype = {
|
|||
collide_with_objects = true,
|
||||
makes_footstep_sound = true,
|
||||
visual = "mesh",
|
||||
automatic_face_movement_dir = false,
|
||||
automatic_face_movement_dir = true,
|
||||
stepheight = 0.6,
|
||||
-- custom properties
|
||||
id = 0,
|
||||
|
@ -28,17 +28,23 @@ mobs.default_prototype = {
|
|||
life_timer = 75,
|
||||
pause_timer = 0,
|
||||
timer = 0,
|
||||
|
||||
-- cache
|
||||
cache_is_standing = nil,
|
||||
cache_find_nearest_player = nil,
|
||||
}
|
||||
|
||||
function mobs.default_prototype:on_activate(staticdata)
|
||||
self.object:set_armor_groups({fleshy = 100 - self.armor})
|
||||
if self.movement == "ground" then
|
||||
if self.movement ~= "air" then
|
||||
self.object:setacceleration({x=0, y=mobs.gravity, z=0})
|
||||
end
|
||||
self.id = math.random(0, 100000)
|
||||
end
|
||||
|
||||
function mobs.default_prototype:on_step(dtime)
|
||||
self.cache_is_standing = nil
|
||||
self.cache_find_nearest_player = nil
|
||||
|
||||
if self.pause_timer <= 0 then
|
||||
if self.destination then
|
||||
|
@ -56,6 +62,13 @@ function mobs.default_prototype:on_step(dtime)
|
|||
if self.movement ~= "air" and not self:is_standing() then
|
||||
self:set_animation("fall", {"jump", "attack", "move_attack"})
|
||||
end
|
||||
if self.movement == "crawl" then
|
||||
if self:is_standing() then
|
||||
self.object:setacceleration({x=0, y=0, z=0})
|
||||
else
|
||||
self.object:setacceleration({x=0, y=mobs.gravity, z=0})
|
||||
end
|
||||
end
|
||||
|
||||
-- Die when morning comes
|
||||
if not defense:is_dark() then
|
||||
|
@ -146,7 +159,8 @@ function mobs.default_prototype:hunt()
|
|||
end
|
||||
|
||||
if direction then
|
||||
self.destination = vector.add(pos, vector.multiply(direction, 1.25))
|
||||
minetest.chat_send_all("dir:" .. minetest.pos_to_string(direction))
|
||||
self.destination = vector.add(pos, vector.multiply(direction, 1.2))
|
||||
else
|
||||
local r = math.max(0, self.attack_range - 2)
|
||||
local dir = vector.direction(nearest.position, self.object:getpos())
|
||||
|
@ -154,7 +168,6 @@ function mobs.default_prototype:hunt()
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function mobs.default_prototype:do_attack(obj)
|
||||
|
@ -167,7 +180,6 @@ function mobs.default_prototype:do_attack(obj)
|
|||
else
|
||||
self:set_animation("attack")
|
||||
end
|
||||
self.object:setyaw(math.atan2(dir.z, dir.x))
|
||||
end
|
||||
self.life_timer = math.min(300, self.life_timer + 60)
|
||||
end
|
||||
|
@ -175,6 +187,7 @@ end
|
|||
function mobs.default_prototype:jump(direction)
|
||||
if self:is_standing() then
|
||||
if direction then
|
||||
direction.y = 0
|
||||
direction = vector.normalize(direction)
|
||||
else
|
||||
direction = {x=0,y=0,z=0}
|
||||
|
@ -184,7 +197,6 @@ function mobs.default_prototype:jump(direction)
|
|||
v.x = direction.x * self.jump_height
|
||||
v.z = direction.z * self.jump_height
|
||||
self.object:setvelocity(vector.add(self.object:getvelocity(), v))
|
||||
self.object:setyaw(math.atan2(direction.z, direction.x))
|
||||
self:set_animation("jump")
|
||||
end
|
||||
end
|
||||
|
@ -195,9 +207,26 @@ function mobs.default_prototype:die()
|
|||
end
|
||||
|
||||
function mobs.default_prototype:is_standing()
|
||||
if self.cache_is_standing ~= nil then
|
||||
return self.cache_is_standing
|
||||
end
|
||||
|
||||
if self.movement == "air" then
|
||||
self.cache_is_standing = false
|
||||
return false
|
||||
end
|
||||
|
||||
if self.movement == "crawl" then
|
||||
local ret = self:calculate_wall_normal() ~= nil
|
||||
self.cache_is_standing = ret
|
||||
return ret
|
||||
end
|
||||
|
||||
if self.object:getvelocity().y ~= 0 then
|
||||
self.cache_is_standing = false
|
||||
return false
|
||||
end
|
||||
|
||||
local p = self.object:getpos()
|
||||
p.y = p.y + self.collisionbox[2] - 0.5
|
||||
local corners = {
|
||||
|
@ -208,10 +237,13 @@ function mobs.default_prototype:is_standing()
|
|||
}
|
||||
for _,c in ipairs(corners) do
|
||||
local node = minetest.get_node_or_nil(c)
|
||||
if not node or minetest.registered_nodes[node.name].walkable and self.object:getvelocity().y == 0 then
|
||||
if not node or minetest.registered_nodes[node.name].walkable then
|
||||
self.cache_is_standing = true
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
self.cache_is_standing = false
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -236,6 +268,10 @@ function mobs.default_prototype:set_animation(name, inhibit)
|
|||
end
|
||||
|
||||
function mobs.default_prototype:find_nearest_player()
|
||||
if self.cache_find_nearest_player ~= nil then
|
||||
return self.cache_find_nearest_player
|
||||
end
|
||||
|
||||
local p = self.object:getpos()
|
||||
local nearest_player = nil
|
||||
local nearest_pos = p
|
||||
|
@ -257,7 +293,41 @@ function mobs.default_prototype:find_nearest_player()
|
|||
end
|
||||
end
|
||||
end
|
||||
return {player=nearest_player, position=nearest_pos, distance=nearest_dist}
|
||||
|
||||
local ret = {player=nearest_player, position=nearest_pos, distance=nearest_dist}
|
||||
self.cache_find_nearest_player = ret
|
||||
return ret
|
||||
end
|
||||
|
||||
function mobs.default_prototype:calculate_wall_normal()
|
||||
local p = self.object:getpos()
|
||||
local normals = {1,0,-1}
|
||||
local xs = {self.collisionbox[1]-0.5,0,self.collisionbox[4]+0.5}
|
||||
local ys = {self.collisionbox[2]-0.5,0,self.collisionbox[5]+0.5}
|
||||
local zs = {self.collisionbox[3]-0.5,0,self.collisionbox[6]+0.5}
|
||||
|
||||
local normal = vector.new()
|
||||
local count = 0
|
||||
for xi=1,3 do
|
||||
for yi=1,3 do
|
||||
for zi=1,3 do
|
||||
if xi ~= 2 and yi ~= 2 and zi ~= 2 then
|
||||
local sp = vector.add(p, {x=xs[xi], y=ys[yi], z=zs[zi]})
|
||||
local node = minetest.get_node_or_nil(sp)
|
||||
if node and minetest.registered_nodes[node.name].walkable then
|
||||
normal = vector.add(normal, {x=normals[xi], y=normals[yi], z=normals[zi]})
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if count > 0 then
|
||||
return vector.normalize(normal)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
mobs.move_method = {}
|
||||
|
@ -279,7 +349,7 @@ function mobs.move_method:air(dtime, destination)
|
|||
if vector.length(v) < self.move_speed * 1.5 then
|
||||
t = math.pow(0.1, dtime)
|
||||
else
|
||||
t = math.pow(0.8, dtime)
|
||||
t = math.pow(0.4, dtime)
|
||||
speed = speed * 0.9
|
||||
end
|
||||
self.object:setvelocity(vector.add(
|
||||
|
@ -288,14 +358,6 @@ function mobs.move_method:air(dtime, destination)
|
|||
))
|
||||
|
||||
if speed > self.move_speed * 0.04 then
|
||||
local yaw = self.object:getyaw()
|
||||
local yaw_delta = math.atan2(delta.z, delta.x) - yaw
|
||||
if yaw_delta < -math.pi then
|
||||
yaw_delta = yaw_delta + math.pi * 2
|
||||
elseif yaw_delta > math.pi then
|
||||
yaw_delta = yaw_delta - math.pi * 2
|
||||
end
|
||||
self.object:setyaw(yaw + yaw_delta * (1-t))
|
||||
self:set_animation("move", {"attack", "move_attack"})
|
||||
else
|
||||
self:set_animation("idle", {"attack", "move_attack"})
|
||||
|
@ -320,7 +382,7 @@ function mobs.move_method:ground(dtime, destination)
|
|||
if self:is_standing() and vector.length(v) < self.move_speed * 4 then
|
||||
t = math.pow(0.001, dtime)
|
||||
else
|
||||
t = math.pow(0.7, dtime)
|
||||
t = math.pow(0.4, dtime)
|
||||
speed = speed * 0.9
|
||||
end
|
||||
local dir = vector.normalize(delta)
|
||||
|
@ -335,10 +397,10 @@ function mobs.move_method:ground(dtime, destination)
|
|||
local jump = nil
|
||||
if self.smart_path then
|
||||
local p = self.object:getpos()
|
||||
if destination.y > p.y + 1 then
|
||||
if destination.y > p.y + 0.55 then
|
||||
for y=p.y,p.y+self.jump_height do
|
||||
jump = defense.pathfinder:get_direction(self.name, {x=p.x, y=y, z=p.z})
|
||||
if jump and (jump.x ~= 0 or jump.z ~= 0) then
|
||||
if not jump or (jump.x ~= 0 or jump.z ~= 0) then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -370,14 +432,40 @@ function mobs.move_method:ground(dtime, destination)
|
|||
self:jump(jump)
|
||||
elseif self:is_standing() then
|
||||
if speed > self.move_speed * 0.06 then
|
||||
local yaw = self.object:getyaw()
|
||||
local yaw_delta = math.atan2(dir.z, dir.x) - yaw
|
||||
if yaw_delta < -math.pi then
|
||||
yaw_delta = yaw_delta + math.pi * 2
|
||||
elseif yaw_delta > math.pi then
|
||||
yaw_delta = yaw_delta - math.pi * 2
|
||||
end
|
||||
self.object:setyaw(yaw + yaw_delta * (1-t))
|
||||
self:set_animation("move", {"move_attack"})
|
||||
else
|
||||
self:set_animation("idle", {"attack", "move_attack"})
|
||||
end
|
||||
end
|
||||
end
|
||||
function mobs.move_method:crawl(dtime, destination)
|
||||
local delta = vector.subtract(destination, self.object:getpos())
|
||||
local dist = vector.length(delta)
|
||||
|
||||
local speed = self.move_speed * math.max(0, math.min(1, 1.2 * dist))
|
||||
local t
|
||||
local v = self.object:getvelocity()
|
||||
if self:is_standing() and vector.length(v) < self.move_speed * 4 then
|
||||
t = math.pow(0.001, dtime)
|
||||
else
|
||||
t = math.pow(0.4, dtime)
|
||||
speed = speed * 0.9
|
||||
end
|
||||
|
||||
local wall = self:calculate_wall_normal()
|
||||
if wall and dist > 0 then
|
||||
local dot = math.abs(wall.x * delta.x + wall.y * delta.y + wall.z * delta.z)
|
||||
delta = vector.add(delta, vector.multiply(wall, -dot))
|
||||
end
|
||||
local dir = vector.normalize(delta)
|
||||
local v2 = vector.add(
|
||||
vector.multiply(v, t),
|
||||
vector.multiply(dir, speed * (1-t))
|
||||
)
|
||||
self.object:setvelocity(v2)
|
||||
|
||||
if self:is_standing() then
|
||||
if speed > self.move_speed * 0.06 then
|
||||
self:set_animation("move", {"move_attack"})
|
||||
else
|
||||
self:set_animation("idle", {"attack", "move_attack"})
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
minetest.register_entity("defense:aranay_proxy", {
|
||||
physical = false,
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
visual = "mesh",
|
||||
mesh = "defense_aranay.b3d",
|
||||
textures = {"defense_aranay.png"},
|
||||
|
||||
parent = nil,
|
||||
timer = 0.5,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
if self.timer > 0 then
|
||||
self.timer = self.timer - dtime
|
||||
else
|
||||
local active_parent = false
|
||||
-- The engine does not provide a simple way to check if an entity is still alive
|
||||
for _,e in pairs(minetest.luaentities) do
|
||||
if e == self.parent then
|
||||
active_parent = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not active_parent or not self.parent then
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
local function dot(a, b)
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z
|
||||
end
|
||||
|
||||
local function cross(a, b)
|
||||
return {
|
||||
x=a.y*b.z - a.z*b.y,
|
||||
z=a.z*b.x - a.x*b.z,
|
||||
y=a.x*b.y - a.y*b.x
|
||||
}
|
||||
end
|
||||
|
||||
local function calculate_rotation(dir, up)
|
||||
-- http://stackoverflow.com/a/21627251
|
||||
local angle_h = math.atan2(dir.z, dir.x)
|
||||
local angle_p = math.asin(dir.y)
|
||||
local w0 = vector.normalize({x=dir.z, y=0, z=-dir.x})
|
||||
local u0 = cross(w0, dir)
|
||||
local angle_b = math.atan2(dot(w0,up), dot(u0,up))
|
||||
return {x=angle_p, y=angle_h, z=angle_b}
|
||||
end
|
||||
|
||||
defense.mobs.register_mob("defense:aranay", {
|
||||
hp_max = 6,
|
||||
collisionbox = {-0.4,-0.01,-0.4, 0.4,0.8,0.4},
|
||||
mesh = "defense_aranay_core.b3d",
|
||||
makes_footstep_sound = true,
|
||||
automatic_face_movement_dir = false,
|
||||
|
||||
animation = {
|
||||
idle = {a=0, b=19, rate=20},
|
||||
jump = {a=20, b=39, rate=5},
|
||||
fall = {a=20, b=39, rate=5},
|
||||
attack = {a=60, b=69, rate=20},
|
||||
move = {a=20, b=39, rate=40},
|
||||
move_attack = {a=40, b=59, rate=20},
|
||||
},
|
||||
|
||||
mass = 3,
|
||||
movement = "crawl",
|
||||
move_speed = 3,
|
||||
armor = 0,
|
||||
attack_damage = 1,
|
||||
attack_range = 1.5,
|
||||
attack_interval = 0.8,
|
||||
|
||||
proxy = nil,
|
||||
rotation = {x=0, y=0, z=0},
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
defense.mobs.default_prototype.on_activate(self, staticdata)
|
||||
|
||||
self.proxy = minetest.add_entity(self.object:getpos(), "defense:aranay_proxy")
|
||||
self.proxy:get_luaentity().parent = self
|
||||
self.proxy:set_attach(self.object, "", {x=0, y=0, z=0}, {x=0, y=0, z=0})
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
defense.mobs.default_prototype.on_step(self, dtime)
|
||||
self:hunt()
|
||||
|
||||
-- Rotation
|
||||
if vector.length(self.object:getvelocity()) > 0.6 then
|
||||
local wall = self:calculate_wall_normal()
|
||||
if wall then
|
||||
local dir = vector.normalize(self.object:getvelocity())
|
||||
local abs_dot = math.abs(dot(dir, wall))
|
||||
local up = vector.normalize(vector.add(wall, vector.multiply(dir, -abs_dot)))
|
||||
local rot = calculate_rotation(dir, up)
|
||||
self.rotation = vector.multiply(rot, -180/math.pi)
|
||||
end
|
||||
self.proxy:set_attach(self.object, "", {x=0, y=0, z=0}, self.rotation)
|
||||
end
|
||||
end,
|
||||
|
||||
set_animation = function(self, name, inhibit)
|
||||
if self.current_animation == name then
|
||||
return
|
||||
end
|
||||
if inhibit then
|
||||
for _,p in ipairs(inhibit) do
|
||||
if self.current_animation == p and self.timer < self.current_animation_end then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local anim_prop = self.animation[name]
|
||||
if anim_prop then
|
||||
self.current_animation = name
|
||||
self.current_animation_end = self.timer + (anim_prop.b - anim_prop.a - 1) / anim_prop.rate
|
||||
self.proxy:set_animation({x=anim_prop.a, y=anim_prop.b}, anim_prop.rate, 0)
|
||||
end
|
||||
end,
|
||||
})
|
Binary file not shown.
Binary file not shown.
|
@ -29,17 +29,18 @@ function pathfinder:register_class(class, properties)
|
|||
end
|
||||
|
||||
-- Returns a number
|
||||
-- function pathfinder:get_distance(class, position)
|
||||
-- local field = self:get_field(class, position)
|
||||
-- if not field then
|
||||
-- return nil
|
||||
-- end
|
||||
-- return field.distance
|
||||
-- end
|
||||
function pathfinder:get_distance(class, position)
|
||||
local field = self:get_field(class, position)
|
||||
if not field then
|
||||
return nil
|
||||
end
|
||||
return field.distance
|
||||
end
|
||||
|
||||
-- Returns a vector
|
||||
function pathfinder:get_direction(class, position)
|
||||
local directions = {
|
||||
[0]={x=0, y=0, z=0},
|
||||
{x=0, y=-1, z=0},
|
||||
{x=0, y=1, z=0},
|
||||
{x=0, y=0, z=-1},
|
||||
|
@ -50,24 +51,25 @@ function pathfinder:get_direction(class, position)
|
|||
|
||||
local total = vector.new(0, 0, 0)
|
||||
local count = 0
|
||||
local time = minetest.get_gametime()
|
||||
|
||||
local ipos = {x=math.floor(position.x), y=math.floor(position.y), z=math.floor(position.z)}
|
||||
local cells = {
|
||||
position,
|
||||
{x=position.x + 1, y=position.y, z=position.z},
|
||||
{x=position.x - 1, y=position.y, z=position.z},
|
||||
{x=position.x, y=position.y + 1, z=position.z},
|
||||
{x=position.x, y=position.y - 1, z=position.z},
|
||||
{x=position.x, y=position.y, z=position.z + 1},
|
||||
{x=position.x, y=position.y, z=position.z - 1},
|
||||
ipos,
|
||||
{x=ipos.x + 1, y=ipos.y, z=ipos.z},
|
||||
{x=ipos.x - 1, y=ipos.y, z=ipos.z},
|
||||
{x=ipos.x, y=ipos.y + 1, z=ipos.z},
|
||||
{x=ipos.x, y=ipos.y - 1, z=ipos.z},
|
||||
{x=ipos.x, y=ipos.y, z=ipos.z + 1},
|
||||
{x=ipos.x, y=ipos.y, z=ipos.z - 1},
|
||||
}
|
||||
for _,p in ipairs(cells) do
|
||||
local field = self:get_field(class, p)
|
||||
if field then
|
||||
local last_time = player_last_update[field.player] or field.time
|
||||
if last_time + field.distance * 4 > time then
|
||||
if field.time + field.distance * 4 > last_time then
|
||||
local direction = directions[field.direction]
|
||||
total = vector.add(total, direction)
|
||||
local weight = 1/(1 + field.distance)
|
||||
total = vector.add(total, vector.multiply(direction, weight))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -80,11 +82,16 @@ function pathfinder:get_direction(class, position)
|
|||
end
|
||||
|
||||
-- Returns a table {time, distance}
|
||||
function pathfinder:get_field(class, position)
|
||||
function pathfinder:get_field(class, position, no_position_adjust)
|
||||
local collisionbox = self.classes[class].collisionbox
|
||||
local x = math.floor(position.x + collisionbox[1] + 0.01)
|
||||
local y = math.floor(position.y + collisionbox[2] + 0.01)
|
||||
local z = math.floor(position.z + collisionbox[3] + 0.01)
|
||||
if not no_position_adjust then
|
||||
position.x = position.x + collisionbox[1] + 0.01
|
||||
position.y = position.y + collisionbox[2] + 0.01
|
||||
position.z = position.z + collisionbox[3] + 0.01
|
||||
end
|
||||
local x = math.floor(position.x)
|
||||
local y = math.floor(position.y)
|
||||
local z = math.floor(position.z)
|
||||
|
||||
local chunk_key = math.floor(x/chunk_size) ..
|
||||
":" .. math.floor(y/chunk_size) ..
|
||||
|
@ -101,11 +108,16 @@ function pathfinder:get_field(class, position)
|
|||
return chunk[index]
|
||||
end
|
||||
|
||||
function pathfinder:set_field(class, position, player, distance, direction, time)
|
||||
function pathfinder:set_field(class, position, player, distance, direction, time, no_position_adjust)
|
||||
local collisionbox = self.classes[class].collisionbox
|
||||
local x = math.floor(position.x + collisionbox[1] + 0.01)
|
||||
local y = math.floor(position.y + collisionbox[2] + 0.01)
|
||||
local z = math.floor(position.z + collisionbox[3] + 0.01)
|
||||
if not no_position_adjust then
|
||||
position.x = position.x + collisionbox[1] + 0.01
|
||||
position.y = position.y + collisionbox[2] + 0.01
|
||||
position.z = position.z + collisionbox[3] + 0.01
|
||||
end
|
||||
local x = math.floor(position.x)
|
||||
local y = math.floor(position.y)
|
||||
local z = math.floor(position.z)
|
||||
|
||||
local chunk_key = math.floor(x/chunk_size) ..
|
||||
":" .. math.floor(y/chunk_size) ..
|
||||
|
@ -125,9 +137,9 @@ end
|
|||
|
||||
function pathfinder:delete_field(class, position)
|
||||
local collisionbox = self.classes[class].collisionbox
|
||||
local x = math.floor(position.x + collisionbox[1] + 0.01)
|
||||
local y = math.floor(position.y + collisionbox[2] + 0.01)
|
||||
local z = math.floor(position.z + collisionbox[3] + 0.01)
|
||||
local x = math.floor(position.x)
|
||||
local y = math.floor(position.y)
|
||||
local z = math.floor(position.z)
|
||||
|
||||
local chunk_key = math.floor(x/chunk_size) ..
|
||||
":" .. math.floor(y/chunk_size) ..
|
||||
|
@ -178,19 +190,21 @@ function pathfinder:update(dtime)
|
|||
local current = Queue.pop(vq)
|
||||
for di,n in ipairs(neighborhood) do
|
||||
local npos = vector.add(current.position, n)
|
||||
npos.x = math.floor(npos.x)
|
||||
npos.y = math.floor(npos.y)
|
||||
npos.z = math.floor(npos.z)
|
||||
npos.x = math.floor(npos.x + 0.5)
|
||||
npos.y = math.floor(npos.y + 0.5)
|
||||
npos.z = math.floor(npos.z + 0.5)
|
||||
local cost = class.cost_method(class, npos, current.position)
|
||||
if cost and cost < self.path_max_range_far then
|
||||
local next_distance = current.distance + cost
|
||||
local neighbor_field = self:get_field(c, npos)
|
||||
if not neighbor_field
|
||||
or neighbor_field.time < current.time
|
||||
and neighbor_field.direction ~= di
|
||||
or neighbor_field.time == current.time
|
||||
and neighbor_field.distance > next_distance then
|
||||
self:set_field(c, npos, current.player, next_distance, di, current.time)
|
||||
local neighbor_field = self:get_field(c, npos, true)
|
||||
if not neighbor_field or
|
||||
neighbor_field.time < current.time and
|
||||
neighbor_field.direction ~= di or
|
||||
neighbor_field.time == current.time and
|
||||
(neighbor_field.distance > next_distance or
|
||||
neighbor_field.distance == next_distance and
|
||||
math.random() < 0.5) then
|
||||
self:set_field(c, npos, current.player, next_distance, di, current.time, true)
|
||||
if next_distance < self.path_max_range or current.far and next_distance < self.path_max_range_far then
|
||||
if size < 800 then
|
||||
Queue.push(vq, {
|
||||
|
@ -235,12 +249,12 @@ function pathfinder:update(dtime)
|
|||
for _,p in ipairs(minetest.get_connected_players()) do
|
||||
local pos = p:getpos()
|
||||
for c,_ in pairs(self.classes) do
|
||||
for y=pos.y-0.5,pos.y+0.5 do
|
||||
for y=math.floor(pos.y),math.ceil(pos.y) do
|
||||
local tp = {x=pos.x, y=y, z=pos.z}
|
||||
local field = self:get_field(c, tp)
|
||||
if not field or field.distance > 0 then
|
||||
local name = p:get_player_name()
|
||||
self:set_field(c, tp, name, 0, 4, time)
|
||||
self:set_field(c, tp, name, 0, 0, time)
|
||||
Queue.push(visit_queues[c], {position=tp, player=name, distance=0, direction=0, time=time})
|
||||
player_last_update[name] = time
|
||||
end
|
||||
|
@ -251,7 +265,7 @@ end
|
|||
|
||||
pathfinder.cost_method = {}
|
||||
function pathfinder.cost_method.air(class, pos, parent)
|
||||
-- Check if solid
|
||||
-- Check if in solid
|
||||
for y=pos.y,pos.y+class.size.y-1 do
|
||||
for z=pos.z,pos.z+class.size.z-1 do
|
||||
for x=pos.x,pos.x+class.size.x-1 do
|
||||
|
@ -309,7 +323,7 @@ function pathfinder.cost_method.ground(class, pos, parent)
|
|||
local node = minetest.get_node_or_nil(l)
|
||||
if not node then return nil end
|
||||
if minetest.registered_nodes[node.name].walkable then
|
||||
return ground_distance
|
||||
return 1 + ground_distance
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -324,6 +338,69 @@ function pathfinder.cost_method.ground(class, pos, parent)
|
|||
|
||||
return 1
|
||||
end
|
||||
function pathfinder.cost_method.crawl(class, pos, parent)
|
||||
-- Check if in solid
|
||||
for y=pos.y,pos.y+class.size.y-1 do
|
||||
for z=pos.z,pos.z+class.size.z-1 do
|
||||
for x=pos.x,pos.x+class.size.x-1 do
|
||||
local node = minetest.get_node_or_nil({x=x, y=y, z=z})
|
||||
if not node then return nil end
|
||||
if minetest.registered_nodes[node.name].walkable then
|
||||
return math.huge
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if touching solid
|
||||
-- xz-plane
|
||||
for x=pos.x-1,pos.x+class.size.x do
|
||||
for z=pos.z-1,pos.z+class.size.z do
|
||||
local node_n = minetest.get_node_or_nil({x=x, y=pos.y-1, z=z})
|
||||
if not node_n then return nil end
|
||||
if minetest.registered_nodes[node_n.name].walkable then
|
||||
return 1
|
||||
end
|
||||
local node_p = minetest.get_node_or_nil({x=x, y=pos.y+class.size.y, z=z})
|
||||
if not node_p then return nil end
|
||||
if minetest.registered_nodes[node_p.name].walkable then
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
-- xy-plane
|
||||
for x=pos.x,pos.x+class.size.x-1 do
|
||||
for y=pos.y,pos.y+class.size.y-1 do
|
||||
local node_n = minetest.get_node_or_nil({x=x, y=y, z=pos.z-1})
|
||||
if not node_n then return nil end
|
||||
if minetest.registered_nodes[node_n.name].walkable then
|
||||
return 1
|
||||
end
|
||||
local node_p = minetest.get_node_or_nil({x=x, y=y, z=pos.z+class.size.z})
|
||||
if not node_p then return nil end
|
||||
if minetest.registered_nodes[node_p.name].walkable then
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
-- yz-plane
|
||||
for y=pos.y,pos.y+class.size.y-1 do
|
||||
for z=pos.z,pos.z+class.size.z-1 do
|
||||
local node_n = minetest.get_node_or_nil({x=pos.x-1, y=y, z=z})
|
||||
if not node_n then return nil end
|
||||
if minetest.registered_nodes[node_n.name].walkable then
|
||||
return 1
|
||||
end
|
||||
local node_p = minetest.get_node_or_nil({x=pos.x+class.size.z, y=y, z=z})
|
||||
if not node_p then return nil end
|
||||
if minetest.registered_nodes[node_p.name].walkable then
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return math.huge
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
pathfinder:update(dtime)
|
||||
|
|
Loading…
Reference in New Issue