Spawner: Find entrance doors (WIP)
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								npc.lua
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								spawner.lua
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								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,
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user