Teach villagers to open and walk through doors
This commit is contained in:
parent
5542edf5d9
commit
eb30490dff
@ -75,7 +75,7 @@ end
|
|||||||
|
|
||||||
rp_mobs.microtasks = {}
|
rp_mobs.microtasks = {}
|
||||||
|
|
||||||
rp_mobs.microtasks.pathfind_and_walk_to = function(target_pos, walk_speed, jump_strength, set_yaw, searchdistance, max_jump, max_drop)
|
rp_mobs.microtasks.pathfind_and_walk_to = function(start_pos, target_pos, walk_speed, jump_strength, set_yaw, searchdistance, max_jump, max_drop)
|
||||||
local mtask = {}
|
local mtask = {}
|
||||||
mtask.label = "pathfind and walk to coordinate"
|
mtask.label = "pathfind and walk to coordinate"
|
||||||
mtask.on_start = function(self, mob)
|
mtask.on_start = function(self, mob)
|
||||||
@ -89,8 +89,10 @@ rp_mobs.microtasks.pathfind_and_walk_to = function(target_pos, walk_speed, jump_
|
|||||||
self.statedata.stuck_last_position = nil
|
self.statedata.stuck_last_position = nil
|
||||||
self.statedata.stuck_recheck_timer = 0
|
self.statedata.stuck_recheck_timer = 0
|
||||||
|
|
||||||
local start_pos = mob.object:get_pos()
|
if not start_pos then
|
||||||
start_pos.y = math.floor(start_pos.y)
|
start_pos = mob.object:get_pos()
|
||||||
|
start_pos.y = math.floor(start_pos.y)
|
||||||
|
end
|
||||||
start_pos = vector.round(start_pos)
|
start_pos = vector.round(start_pos)
|
||||||
local path = minetest.find_path(start_pos, target_pos, searchdistance, max_jump, max_drop, "A*")
|
local path = minetest.find_path(start_pos, target_pos, searchdistance, max_jump, max_drop, "A*")
|
||||||
self.statedata.path = path
|
self.statedata.path = path
|
||||||
|
@ -101,13 +101,24 @@ end
|
|||||||
-- This algorithm performs up to 5 path searches so it is less efficient
|
-- This algorithm performs up to 5 path searches so it is less efficient
|
||||||
-- than calling minetest.find_path.
|
-- than calling minetest.find_path.
|
||||||
--
|
--
|
||||||
-- Returns: list of paths on success, nil on failure.
|
-- Returns: Lists of 'goals' the mob has to reach to get to the
|
||||||
|
-- destination. Each goal is a table with a 'goal_type' field and other fields.
|
||||||
|
-- Possible goal types:
|
||||||
|
--
|
||||||
|
-- { goal_type = "path", path = <path> }
|
||||||
|
-- Path goal. path is a list of positions the mob has to walk in that order
|
||||||
|
--
|
||||||
|
-- { goal_type = "door", pos = <door position> }
|
||||||
|
-- Door obstacle. Mob may have to interact with the door in order to
|
||||||
|
-- get through. pos is the position of the lower door segment.
|
||||||
|
--
|
||||||
|
-- If no path was found, returns nil.
|
||||||
local find_path_advanced = function(pos1, pos2, searchdistance, max_jump, max_drop)
|
local find_path_advanced = function(pos1, pos2, searchdistance, max_jump, max_drop)
|
||||||
local algorithm = "A*_noprefetch"
|
local algorithm = "A*_noprefetch"
|
||||||
-- First check if we can find a direct path
|
-- First check if we can find a direct path
|
||||||
local path = minetest.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algorithm)
|
local path = minetest.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algorithm)
|
||||||
if path then
|
if path then
|
||||||
return { path }
|
return { { goal_type = "path", path = path } }
|
||||||
end
|
end
|
||||||
local doorarea_min = vector.add(pos2, vector.new(-12, -6, -12))
|
local doorarea_min = vector.add(pos2, vector.new(-12, -6, -12))
|
||||||
local doorarea_max = vector.add(pos2, vector.new(12, 6, 12))
|
local doorarea_max = vector.add(pos2, vector.new(12, 6, 12))
|
||||||
@ -172,8 +183,12 @@ local find_path_advanced = function(pos1, pos2, searchdistance, max_jump, max_dr
|
|||||||
if path1 then
|
if path1 then
|
||||||
local path2 = minetest.find_path(splitpos2, pos2, searchdistance, max_jump, max_drop, algorithm)
|
local path2 = minetest.find_path(splitpos2, pos2, searchdistance, max_jump, max_drop, algorithm)
|
||||||
if path2 then
|
if path2 then
|
||||||
-- Both paths found. Return them
|
-- Both paths found. Join them by putting the door between them
|
||||||
return { path1, path2 }
|
return {
|
||||||
|
{ goal_type = "path", path = path1 },
|
||||||
|
{ goal_type = "door", pos = doorpos },
|
||||||
|
{ goal_type = "path", path = path2 },
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- On failure, try it again but do it from start to the *other* side of the door (splitpos2) first.
|
-- On failure, try it again but do it from start to the *other* side of the door (splitpos2) first.
|
||||||
@ -181,7 +196,11 @@ local find_path_advanced = function(pos1, pos2, searchdistance, max_jump, max_dr
|
|||||||
if path3 then
|
if path3 then
|
||||||
local path4 = minetest.find_path(splitpos1, splitpos2, searchdistance, max_jump, max_drop, algorithm)
|
local path4 = minetest.find_path(splitpos1, splitpos2, searchdistance, max_jump, max_drop, algorithm)
|
||||||
if path4 then
|
if path4 then
|
||||||
return { path3, path4 }
|
return {
|
||||||
|
{ goal_type = "path", path = path3 },
|
||||||
|
{ goal_type = "door", pos = doorpos },
|
||||||
|
{ goal_type = "path", path = path4 },
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -247,9 +266,9 @@ local find_reachable_node = function(startpos, nodenames, searchdistance, under_
|
|||||||
searchpos = npos
|
searchpos = npos
|
||||||
end
|
end
|
||||||
if searchpos then
|
if searchpos then
|
||||||
local path_to_node = find_path_advanced(startpos, searchpos, searchdistance, MAX_JUMP, MAX_DROP)
|
local goals = find_path_advanced(startpos, searchpos, searchdistance, MAX_JUMP, MAX_DROP)
|
||||||
if path_to_node then
|
if goals then
|
||||||
return npos, path_to_node
|
return npos, goals
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
table.remove(nodes, r)
|
table.remove(nodes, r)
|
||||||
@ -281,6 +300,18 @@ local microtask_find_new_home_bed = rp_mobs.create_microtask({
|
|||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local create_microtask_open_door = function(door_pos)
|
||||||
|
return rp_mobs.create_microtask({
|
||||||
|
label = "open door",
|
||||||
|
singlestep = true,
|
||||||
|
on_step = function(self, mob)
|
||||||
|
if door.is_open(door_pos) == false then
|
||||||
|
door.toggle_door(door_pos)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
local movement_decider = function(task_queue, mob)
|
local movement_decider = function(task_queue, mob)
|
||||||
local task_stand = rp_mobs.create_task({label="stand still"})
|
local task_stand = rp_mobs.create_task({label="stand still"})
|
||||||
local yaw = math.random(0, 360) / 360 * (math.pi*2)
|
local yaw = math.random(0, 360) / 360 * (math.pi*2)
|
||||||
@ -302,15 +333,17 @@ local movement_decider = function(task_queue, mob)
|
|||||||
if mob._custom_state.home_bed then
|
if mob._custom_state.home_bed then
|
||||||
local mobpos = mob.object:get_pos()
|
local mobpos = mob.object:get_pos()
|
||||||
local searchpos = find_free_horizontal_neighbor(mob._custom_state.home_bed)
|
local searchpos = find_free_horizontal_neighbor(mob._custom_state.home_bed)
|
||||||
local pathlist_to_bed = find_path_advanced(mobpos, searchpos, HOME_BED_PATHFIND_DISTANCE, MAX_JUMP, MAX_DROP)
|
local goals = find_path_advanced(mobpos, searchpos, HOME_BED_PATHFIND_DISTANCE, MAX_JUMP, MAX_DROP)
|
||||||
if pathlist_to_bed then
|
if goals then
|
||||||
local path = pathlist_to_bed[1]
|
if goals[1] and goals[1].goal_type == "path" then
|
||||||
local target = path[#path]
|
local path = goals[1].path
|
||||||
local mt_walk_to_bed = rp_mobs.microtasks.pathfind_and_walk_to(target, WALK_SPEED, JUMP_STRENGTH, true, HOME_BED_PATHFIND_DISTANCE, MAX_JUMP, MAX_DROP)
|
local target = path[#path]
|
||||||
mt_walk_to_bed.start_animation = "walk"
|
local mt_walk_to_bed = rp_mobs.microtasks.pathfind_and_walk_to(nil, target, WALK_SPEED, JUMP_STRENGTH, true, HOME_BED_PATHFIND_DISTANCE, MAX_JUMP, MAX_DROP)
|
||||||
local task_walk_to_bed = rp_mobs.create_task({label="walk to bed"})
|
mt_walk_to_bed.start_animation = "walk"
|
||||||
rp_mobs.add_microtask_to_task(mob, mt_walk_to_bed, task_walk_to_bed)
|
local task_walk_to_bed = rp_mobs.create_task({label="walk to bed"})
|
||||||
rp_mobs.add_task_to_task_queue(task_queue, task_walk_to_bed)
|
rp_mobs.add_microtask_to_task(mob, mt_walk_to_bed, task_walk_to_bed)
|
||||||
|
rp_mobs.add_task_to_task_queue(task_queue, task_walk_to_bed)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif day_phase == "day" then
|
elseif day_phase == "day" then
|
||||||
@ -357,14 +390,29 @@ local movement_decider = function(task_queue, mob)
|
|||||||
if targetnodes then
|
if targetnodes then
|
||||||
-- Go to workplace/recreational node at day
|
-- Go to workplace/recreational node at day
|
||||||
local mobpos = mob.object:get_pos()
|
local mobpos = mob.object:get_pos()
|
||||||
local targetpos, pathlist_to_target = find_reachable_node(mobpos, targetnodes, WORK_DISTANCE, under_air)
|
local targetpos, goals = find_reachable_node(mobpos, targetnodes, WORK_DISTANCE, under_air)
|
||||||
if targetpos and pathlist_to_target then
|
if targetpos and goals and #goals > 0 then
|
||||||
local path = pathlist_to_target[1]
|
|
||||||
local target = path[#path]
|
|
||||||
local mt_walk_to_target = rp_mobs.microtasks.pathfind_and_walk_to(target, WALK_SPEED, JUMP_STRENGTH, true, WORK_DISTANCE, MAX_JUMP, MAX_DROP)
|
|
||||||
mt_walk_to_target.start_animation = "walk"
|
|
||||||
local task_walk_to_target = rp_mobs.create_task({label="walk to recreation/workplace"})
|
local task_walk_to_target = rp_mobs.create_task({label="walk to recreation/workplace"})
|
||||||
rp_mobs.add_microtask_to_task(mob, mt_walk_to_target, task_walk_to_target)
|
for g=1, #goals do
|
||||||
|
local goal = goals[g]
|
||||||
|
-- Open door
|
||||||
|
if goal.goal_type == "door" then
|
||||||
|
local mt_open_door = create_microtask_open_door(goal.pos)
|
||||||
|
mt_open_door.start_animation = "idle"
|
||||||
|
rp_mobs.add_microtask_to_task(mob, mt_open_door, task_walk_to_target)
|
||||||
|
-- Traverse path
|
||||||
|
elseif goal.goal_type == "path" then
|
||||||
|
local path = goal.path
|
||||||
|
local target = path[#path]
|
||||||
|
local start = path[1]
|
||||||
|
local mt_walk_to_target = rp_mobs.microtasks.pathfind_and_walk_to(start, target, WALK_SPEED, JUMP_STRENGTH, true, WORK_DISTANCE, MAX_JUMP, MAX_DROP)
|
||||||
|
mt_walk_to_target.start_animation = "walk"
|
||||||
|
rp_mobs.add_microtask_to_task(mob, mt_walk_to_target, task_walk_to_target)
|
||||||
|
else
|
||||||
|
minetest.log("error", "[rp_mobs_mobs] Villager walk algorithm: Invalid goal_type!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
rp_mobs.add_task_to_task_queue(task_queue, task_walk_to_target)
|
rp_mobs.add_task_to_task_queue(task_queue, task_walk_to_target)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name = rp_mobs_mobs
|
name = rp_mobs_mobs
|
||||||
title = Repixture Mobs
|
title = Repixture Mobs
|
||||||
description = Repixture Mobs: Mob definitions, behavior, graphics, models, sounds
|
description = Repixture Mobs: Mob definitions, behavior, graphics, models, sounds
|
||||||
depends = rp_mobs, rp_achievements, rp_tnt
|
depends = rp_mobs, rp_achievements, rp_tnt, rp_door
|
||||||
optional_depends = rp_nav
|
optional_depends = rp_nav
|
||||||
|
Loading…
x
Reference in New Issue
Block a user