From a667f538f85b8c9ace01536f3eedbf4ebc44cb6a Mon Sep 17 00:00:00 2001 From: Zorman2000 Date: Sat, 8 Apr 2017 10:21:51 -0400 Subject: [PATCH] Spawner: Find entrance doors (WIP) --- actions/pathfinder.lua | 4 +-- actions/places.lua | 61 +++++++++++++++++++++++++---------------- npc.lua | 6 ++-- spawner.lua | 62 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 99 insertions(+), 34 deletions(-) diff --git a/actions/pathfinder.lua b/actions/pathfinder.lua index 562d3a6..38aed11 100644 --- a/actions/pathfinder.lua +++ b/actions/pathfinder.lua @@ -140,7 +140,7 @@ function pathfinder.create_map(start_pos, end_pos, extra_range, walkables) else -- Check if node is walkable local node = minetest.get_node(current_pos) - if node.name == "default:air" then + if node.name == "air" then -- If air do no more checks table.insert(current_row, {pos=current_pos, type=pathfinder.node_types.walkable}) else @@ -181,7 +181,7 @@ end -- for the pathfinding algorithm to use function pathfinder.find_start_and_end_pos(map) -- This is for debug - --print_map(map) + print_map(map) local result = {} for z,row in pairs(map) do for x,node in pairs(row) do diff --git a/actions/places.lua b/actions/places.lua index d7a121c..e61ec1f 100644 --- a/actions/places.lua +++ b/actions/places.lua @@ -132,35 +132,50 @@ function npc.places.find_node_in_area(start_pos, end_pos, type) end -- Specialized function to find doors that are an entrance to a building. --- The criteria for an entrance door is the following: --- - Node in front and above door is air, or --- - Node two nodes from front of door and above door is air and, --- - Up to two nodes above is air --- This needs to be fine-tuned with more practical scenarios. --- The given position is assumed to be the openable node's lower node --- (in the case of doors which have two-node heights) -function npc.places.openable_node_is_entrance(pos) - local result = false - -- Calculate the first position to check - -- Need to get the direction of the openable node - local node = minetest.get_node(pos) - local x_adj = 0 - local z_adj = 0 - minetest.log(node.param2) - if node.param2 then - if node.param2 == 0 then +-- The definition of an entrance is: +-- The openable node with the shortest path to the plotmarker node +-- Based on this definition, other entrances aren't going to be used +-- by the NPC to get into the building +function npc.places.find_entrance_from_openable_nodes(openable_nodes, marker_pos) + local result = nil + local min = 100 - elseif node.param2 == 1 then + for i = 1, #openable_nodes do + local open_pos = openable_nodes[i].node_pos + -- Get node name - check if this node is a 'door'. The way to check + -- is by explicitly checking for 'door' string + local name = minetest.get_node(open_pos).name + local start_i, end_i = string.find(name, "door") + if start_i ~= nil then + -- Define start and end pos + local start_pos, end_pos = open_pos, marker_pos + -- Check if there's any difference in vertical position + minetest.log("Openable node pos: "..minetest.pos_to_string(open_pos)) + minetest.log("Plotmarker node pos: "..minetest.pos_to_string(marker_pos)) - elseif node.param2 == 2 then + if open_pos.y ~= marker_pos.y then + -- Adjust to make pathfinder find nodes one node above + start_pos.y = marker_pos.y + end - elseif node.param2 == 3 then + start_pos.y = start_pos.y + 1 + end_pos.y = end_pos.y + 1 + -- Find path from the openable node to the plotmarker + local path = pathfinder.find_path(start_pos, end_pos, 20, {}) + if path ~= nil then + minetest.log("Path distance: "..dump(#path)) + -- Check if path length is less than the minimum found so far + if #path < min then + -- Set min to path length and the result to the currently found node + min = #path + result = openable_nodes[i] + end + end end end - local y_adj = 2 - local first_check_pos = {x=pos.x + x_adj, y=pos.y + y_adj, z=pos.z + z_adj} - + -- Return result + return result end -- Specialized function to find all sittable nodes supported by the diff --git a/npc.lua b/npc.lua index 36270a5..87e01b9 100755 --- a/npc.lua +++ b/npc.lua @@ -788,7 +788,7 @@ mobs:register_mob("advanced_npc:npc", { -- Added walk chance walk_chance = 30, -- Added stepheight - stepheight = 0., + stepheight = 0.6, walk_velocity = 1, run_velocity = 3, jump = true, @@ -940,11 +940,11 @@ mobs:register_mob("advanced_npc:npc", { time = (time) - (time % 1) -- Check if there is a schedule entry for this time -- Note: Currently only one schedule is supported, for day 0 - minetest.log("Time: "..dump(time)) + --minetest.log("Time: "..dump(time)) local schedule = self.schedules.generic[0] if schedule ~= nil then -- Check if schedule for this time exists - minetest.log("Found default schedule") + --minetest.log("Found default schedule") if schedule[time] ~= nil then -- Check if schedule has a check function if schedule[time].check ~= nil then diff --git a/spawner.lua b/spawner.lua index c4f549b..aed970d 100644 --- a/spawner.lua +++ b/spawner.lua @@ -72,6 +72,7 @@ npc.spawner.spawn_data = { function spawner.get_nodes_by_type(start_pos, end_pos, type) local result = {} local nodes = npc.places.find_node_in_area(start_pos, end_pos, type) + --minetest.log("Found "..dump(#nodes).." nodes of type: "..dump(type)) for _,node_pos in pairs(nodes) do local entry = {} entry["node_pos"] = node_pos @@ -84,10 +85,8 @@ end -- Scans an area for the supported nodes: beds, benches, -- furnaces, storage (e.g. chests) and openable (e.g. doors). -- Returns a table with these classifications -function spawner.scan_area(start_pos, end_pos) - minetest.log("Scanning area for nodes...") - minetest.log("Start pos: "..minetest.pos_to_string(start_pos)) - minetest.log("End pos: "..minetest.pos_to_string(end_pos)) +function spawner.scan_area(pos1, pos2) + local result = { bed_type = {}, sittable_type = {}, @@ -95,7 +94,8 @@ function spawner.scan_area(start_pos, end_pos) storage_type = {}, openable_type = {} } - + local start_pos, end_pos = vector.sort(pos1, pos2) + result.bed_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.BED_TYPE) result.sittable_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.SITTABLE_TYPE) result.furnace_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.FURNACE_TYPE) @@ -230,8 +230,38 @@ function spawner.scan_mg_villages_building(pos, building_data) local x_size = building_data.sizex local y_size = building_data.ysize local z_size = building_data.sizez + local brotate = building_data.brotate local start_pos = {x=pos.x, y=pos.y, z=pos.z} - local end_pos = {x=pos.x + x_size, y=pos.y + y_size, z=pos.z + z_size} + local x_sign, z_sign = 1, 1 + + -- Check plot direction + -- 0 - facing West, -X + -- 1 - facing North, +Z + -- 2 - facing East, +X + -- 3 - facing South -Z + if brotate == 0 then + x_sign, z_sign = 1, -1 + elseif brotate ==1 then + x_sign, z_sign = -1, -1 + local temp = z_size + z_size = x_size + x_size = temp + elseif brotate ==2 then + x_sign, z_sign = -1, -1 + elseif brotate ==3 then + x_sign, z_sign = 1, 1 + end + + minetest.log("Start pos: "..minetest.pos_to_string(start_pos)) + minetest.log("Brotate: "..dump(brotate)) + minetest.log("X_sign: "..dump(x_sign)) + minetest.log("X_adj: "..dump(x_sign*x_size)) + minetest.log("Z_sign: "..dump(z_sign)) + minetest.log("Z_adj: "..dump(z_sign*z_size)) + + local end_pos = {x=pos.x + (x_sign * x_size), y=pos.y + y_size, z=pos.z + (z_sign * z_size)} + + minetest.log("Calculated end pos: "..minetest.pos_to_string(end_pos)) return spawner.scan_area(start_pos, end_pos) end @@ -266,7 +296,12 @@ function spawner.replace_mg_villages_plotmarker(pos) meta:set_string("infotext", infotext) -- Store building type in metadata meta:set_string("building_type", building_type) + -- Store plot information + local plot_info = mg_villages.all_villages[village_id].to_add_data.bpos[plot_nr] + -- minetest.log("Plot info at replacement time: "..dump(plot_info)) + meta:set_string("plot_info", minetest.serialize(plot_info)) -- Scan building for nodes + building_data.brotate = mg_villages.all_villages[village_id].to_add_data.bpos[plot_nr].brotate local nodedata = spawner.scan_mg_villages_building(pos, building_data) -- Store nodedata into the spawner's metadata meta:set_string("node_data", minetest.serialize(nodedata)) @@ -302,6 +337,21 @@ if minetest.get_modpath("mg_villages") ~= nil then groups = {cracky=3,stone=2}, on_rightclick = function( pos, node, clicker, itemstack, pointed_thing) + -- Get all openable-type nodes for this building + local meta = minetest.get_meta(pos) + local doors = minetest.deserialize(meta:get_string("node_data")).openable_type + minetest.log("Found "..dump(#doors).." openable nodes") + + local entrance = npc.places.find_entrance_from_openable_nodes(doors, pos) + if entrance then + minetest.log("Found building entrance at: "..minetest.pos_to_string(entrance.node_pos)) + else + minetest.log("Unable to find building entrance!") + end + + local plot_info = minetest.deserialize(meta:get_string("plot_info")) + minetest.log("Plot info:"..dump(plot_info)) + return mg_villages.plotmarker_formspec( pos, nil, {}, clicker ) end,