diff --git a/mods/rp_mobs/task_templates.lua b/mods/rp_mobs/task_templates.lua index 83b6646e..2d64591e 100644 --- a/mods/rp_mobs/task_templates.lua +++ b/mods/rp_mobs/task_templates.lua @@ -75,7 +75,7 @@ end 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 = {} mtask.label = "pathfind and walk to coordinate" 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_recheck_timer = 0 - local start_pos = mob.object:get_pos() - start_pos.y = math.floor(start_pos.y) + if not start_pos then + start_pos = mob.object:get_pos() + start_pos.y = math.floor(start_pos.y) + end start_pos = vector.round(start_pos) local path = minetest.find_path(start_pos, target_pos, searchdistance, max_jump, max_drop, "A*") self.statedata.path = path diff --git a/mods/rp_mobs_mobs/mobs/villager.lua b/mods/rp_mobs_mobs/mobs/villager.lua index 8a27cf4d..6e24f505 100644 --- a/mods/rp_mobs_mobs/mobs/villager.lua +++ b/mods/rp_mobs_mobs/mobs/villager.lua @@ -101,13 +101,24 @@ end -- This algorithm performs up to 5 path searches so it is less efficient -- 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 goal. path is a list of positions the mob has to walk in that order +-- +-- { goal_type = "door", pos = } +-- 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 algorithm = "A*_noprefetch" -- First check if we can find a direct path local path = minetest.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algorithm) if path then - return { path } + return { { goal_type = "path", path = path } } end local doorarea_min = 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 local path2 = minetest.find_path(splitpos2, pos2, searchdistance, max_jump, max_drop, algorithm) if path2 then - -- Both paths found. Return them - return { path1, path2 } + -- Both paths found. Join them by putting the door between them + return { + { goal_type = "path", path = path1 }, + { goal_type = "door", pos = doorpos }, + { goal_type = "path", path = path2 }, + } end end -- 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 local path4 = minetest.find_path(splitpos1, splitpos2, searchdistance, max_jump, max_drop, algorithm) 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 @@ -247,9 +266,9 @@ local find_reachable_node = function(startpos, nodenames, searchdistance, under_ searchpos = npos end if searchpos then - local path_to_node = find_path_advanced(startpos, searchpos, searchdistance, MAX_JUMP, MAX_DROP) - if path_to_node then - return npos, path_to_node + local goals = find_path_advanced(startpos, searchpos, searchdistance, MAX_JUMP, MAX_DROP) + if goals then + return npos, goals end end table.remove(nodes, r) @@ -281,6 +300,18 @@ local microtask_find_new_home_bed = rp_mobs.create_microtask({ 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 task_stand = rp_mobs.create_task({label="stand still"}) 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 local mobpos = mob.object:get_pos() 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) - if pathlist_to_bed then - local path = pathlist_to_bed[1] - local target = path[#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) - mt_walk_to_bed.start_animation = "walk" - local task_walk_to_bed = rp_mobs.create_task({label="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) + local goals = find_path_advanced(mobpos, searchpos, HOME_BED_PATHFIND_DISTANCE, MAX_JUMP, MAX_DROP) + if goals then + if goals[1] and goals[1].goal_type == "path" then + local path = goals[1].path + local target = path[#path] + 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) + mt_walk_to_bed.start_animation = "walk" + local task_walk_to_bed = rp_mobs.create_task({label="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 elseif day_phase == "day" then @@ -357,14 +390,29 @@ local movement_decider = function(task_queue, mob) if targetnodes then -- Go to workplace/recreational node at day local mobpos = mob.object:get_pos() - local targetpos, pathlist_to_target = find_reachable_node(mobpos, targetnodes, WORK_DISTANCE, under_air) - if targetpos and pathlist_to_target 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 targetpos, goals = find_reachable_node(mobpos, targetnodes, WORK_DISTANCE, under_air) + if targetpos and goals and #goals > 0 then 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) end end diff --git a/mods/rp_mobs_mobs/mod.conf b/mods/rp_mobs_mobs/mod.conf index 5b294a07..3fdf6d0a 100644 --- a/mods/rp_mobs_mobs/mod.conf +++ b/mods/rp_mobs_mobs/mod.conf @@ -1,5 +1,5 @@ name = rp_mobs_mobs title = Repixture Mobs 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