Spawner: Assign entrance door to every NPC spawned.
Increased ABM chance to make NPC spawning less laggy. Improved building scanning, finally now has correct data for scanning nodes. Places: Finding entrances is limited now to MTG doors.
This commit is contained in:
		@@ -113,7 +113,7 @@ function npc.actions.execute(self, command, args)
 | 
			
		||||
		return npc.actions.use_sittable(self, args)
 | 
			
		||||
	elseif command == npc.actions.cmd.WALK_TO_POS then
 | 
			
		||||
		-- Call walk to position task
 | 
			
		||||
		minetest.log("Self: "..dump(self)..", Command: "..dump(command)..", args: "..dump(args))
 | 
			
		||||
		--minetest.log("Self: "..dump(self)..", Command: "..dump(command)..", args: "..dump(args))
 | 
			
		||||
		return npc.actions.walk_to_pos(self, args)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
@@ -603,9 +603,9 @@ function npc.actions.use_sittable(self, args)
 | 
			
		||||
		local pos_out_of_sittable = pos
 | 
			
		||||
		local empty_nodes = npc.places.find_node_orthogonally(pos, {"air"}, 0)
 | 
			
		||||
		if empty_nodes ~= nil and #empty_nodes > 0 then
 | 
			
		||||
			minetest.log("Empty nodes: "..dump(empty_nodes))
 | 
			
		||||
			minetest.log("Npc.actions.get_direction: "..dump(npc.actions.get_direction))
 | 
			
		||||
			minetest.log("Pos: "..dump(pos))
 | 
			
		||||
			--minetest.log("Empty nodes: "..dump(empty_nodes))
 | 
			
		||||
			--minetest.log("Npc.actions.get_direction: "..dump(npc.actions.get_direction))
 | 
			
		||||
			--minetest.log("Pos: "..dump(pos))
 | 
			
		||||
			-- Get direction to the empty node
 | 
			
		||||
			dir = npc.actions.get_direction(pos, empty_nodes[1].pos)
 | 
			
		||||
			-- Calculate position to get out of sittable node
 | 
			
		||||
 
 | 
			
		||||
@@ -73,6 +73,7 @@ local function is_good_node(node, exceptions)
 | 
			
		||||
  -- Is openable is to support doors, fence gates and other
 | 
			
		||||
  -- doors from other mods. Currently, default doors, gates
 | 
			
		||||
  -- and cottages doors are supported.
 | 
			
		||||
  --minetest.log("Is good node: "..dump(node))
 | 
			
		||||
  local is_openable = false
 | 
			
		||||
  for _,node_prefix in pairs(pathfinder.nodes.openable_prefix) do
 | 
			
		||||
    local start_i,end_i = string.find(node.name, node_prefix)
 | 
			
		||||
@@ -140,9 +141,14 @@ function pathfinder.create_map(start_pos, end_pos, extra_range, walkables)
 | 
			
		||||
      else
 | 
			
		||||
        -- Check if node is walkable
 | 
			
		||||
        local node = minetest.get_node(current_pos)
 | 
			
		||||
        -- Check node has air above it
 | 
			
		||||
        local node_above = minetest.get_node({x=current_pos.x, y=current_pos.y+1, z=current_pos.z})
 | 
			
		||||
        if node.name == "air" then
 | 
			
		||||
          -- If air do no more checks
 | 
			
		||||
          table.insert(current_row, {pos=current_pos, type=pathfinder.node_types.walkable})
 | 
			
		||||
          -- Check if node above is air
 | 
			
		||||
          if node.name == "air" then
 | 
			
		||||
            -- If air do no more checks
 | 
			
		||||
            table.insert(current_row, {pos=current_pos, type=pathfinder.node_types.walkable})
 | 
			
		||||
          end
 | 
			
		||||
        else
 | 
			
		||||
          -- Check if it is of a walkable or openable type
 | 
			
		||||
          table.insert(current_row, {pos=current_pos, type=is_good_node(node, walkables)})
 | 
			
		||||
 
 | 
			
		||||
@@ -142,10 +142,24 @@ end
 | 
			
		||||
--   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)
 | 
			
		||||
function npc.places.find_entrance_from_openable_nodes(all_openable_nodes, marker_pos)
 | 
			
		||||
  local result = nil
 | 
			
		||||
  local openable_nodes = {}
 | 
			
		||||
  local min = 100
 | 
			
		||||
 | 
			
		||||
  -- Filter out all other openable nodes except MTG doors.
 | 
			
		||||
  -- Why? For supported village types (which are: medieval, nore
 | 
			
		||||
  -- and logcabin) all buildings use, as the main entrance, 
 | 
			
		||||
  -- a MTG door. Some medieval building have "half_doors" (like farms)
 | 
			
		||||
  -- which NPCs love to confuse with the right building entrance.
 | 
			
		||||
  for i = 1, #all_openable_nodes do
 | 
			
		||||
    local name = minetest.get_node(all_openable_nodes[i].node_pos).name
 | 
			
		||||
    local doors_st, doors_en = string.find(name, "doors:")
 | 
			
		||||
    if doors_st ~= nil then
 | 
			
		||||
      table.insert(openable_nodes, all_openable_nodes[i])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  for i = 1, #openable_nodes do
 | 
			
		||||
 | 
			
		||||
@@ -314,13 +328,13 @@ function npc.places.find_node_behind_door(door_pos)
 | 
			
		||||
    return {x=door_pos.x, y=door_pos.y, z=door_pos.z + 1}
 | 
			
		||||
  elseif door.param2 == 1 then
 | 
			
		||||
    -- Looking east
 | 
			
		||||
    return {x=door_pos.x - 1, y=door_pos.y, z=door_pos.z}
 | 
			
		||||
    return {x=door_pos.x + 1, y=door_pos.y, z=door_pos.z}
 | 
			
		||||
  elseif door.param2 == 2 then
 | 
			
		||||
    -- Looking north
 | 
			
		||||
    return {x=door_pos.x, y=door_pos.y, z=door_pos.z - 1}
 | 
			
		||||
    -- Looking west
 | 
			
		||||
  elseif door.param2 == 3 then
 | 
			
		||||
    return {x=door_pos.x + 1, y=door_pos.y, z=door_pos.z}
 | 
			
		||||
    return {x=door_pos.x - 1, y=door_pos.y, z=door_pos.z}
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@@ -328,17 +342,18 @@ end
 | 
			
		||||
-- front of a door. Used to make NPCs exit buildings.
 | 
			
		||||
function npc.places.find_node_in_front_of_door(door_pos)
 | 
			
		||||
  local door = minetest.get_node(door_pos)
 | 
			
		||||
  minetest.log("Param2 of door: "..dump(door.param2))
 | 
			
		||||
  if door.param2 == 0 then
 | 
			
		||||
    -- Looking south
 | 
			
		||||
    return {x=door_pos.x, y=door_pos.y, z=door_pos.z - 1}
 | 
			
		||||
  elseif door.param2 == 1 then
 | 
			
		||||
    -- Looking east
 | 
			
		||||
    return {x=door_pos.x + 1, y=door_pos.y, z=door_pos.z}
 | 
			
		||||
    return {x=door_pos.x - 1, y=door_pos.y, z=door_pos.z}
 | 
			
		||||
  elseif door.param2 == 2 then
 | 
			
		||||
    -- Looking north
 | 
			
		||||
    return {x=door_pos.x, y=door_pos.y, z=door_pos.z + 1}
 | 
			
		||||
    -- Looking west
 | 
			
		||||
  elseif door.param2 == 3 then
 | 
			
		||||
    return {x=door_pos.x - 1, y=door_pos.y, z=door_pos.z}
 | 
			
		||||
    return {x=door_pos.x + 1, y=door_pos.y, z=door_pos.z}
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										4
									
								
								npc.lua
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								npc.lua
									
									
									
									
									
								
							@@ -333,10 +333,10 @@ function npc.initialize(entity, pos, is_lua_entity)
 | 
			
		||||
    [2] = {task = npc.actions.cmd.USE_SITTABLE, args = {pos=nodes[1], action=npc.actions.const.sittable.SIT} }, 
 | 
			
		||||
    [3] = {action = npc.actions.cmd.FREEZE, args = {freeze = true}}
 | 
			
		||||
  }
 | 
			
		||||
  npc.add_schedule_entry(ent, npc.schedule_types.generic, 0, 7, nil, morning_actions)
 | 
			
		||||
  --npc.add_schedule_entry(ent, npc.schedule_types.generic, 0, 7, nil, morning_actions)
 | 
			
		||||
  --local afternoon_actions = { [1] = {action = npc.actions.stand, args = {}} }
 | 
			
		||||
  local afternoon_actions = {[1] = {task = npc.actions.cmd.USE_SITTABLE, args = {pos=nodes[1], action=npc.actions.const.sittable.GET_UP} } }
 | 
			
		||||
  npc.add_schedule_entry(ent, npc.schedule_types.generic, 0, 9, nil, afternoon_actions)
 | 
			
		||||
  --npc.add_schedule_entry(ent, npc.schedule_types.generic, 0, 9, nil, afternoon_actions)
 | 
			
		||||
  -- local night_actions = {action: npc.action, args: {}}
 | 
			
		||||
  -- npc.add_schedule_entry(self, npc.schedule_type.generic, 0, 19, check, actions)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										75
									
								
								spawner.lua
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								spawner.lua
									
									
									
									
									
								
							@@ -142,18 +142,23 @@ function spawner.assign_places(self, pos)
 | 
			
		||||
 | 
			
		||||
  -- Assign entrance door and related locations
 | 
			
		||||
  if entrance ~= nil and entrance.node_pos ~= nil then
 | 
			
		||||
    -- For debug purposes:
 | 
			
		||||
    --local meta = minetest.get_meta(entrance.node_pos)
 | 
			
		||||
    --meta:set_string("infotext", "Entrance for '"..dump(self.nametag).."': "..dump(entrance.node_pos))
 | 
			
		||||
    --minetest.log("Self: "..dump(self))
 | 
			
		||||
    --minetest.log("Places map: "..dump(self.places_map))
 | 
			
		||||
    npc.places.add_public(self, npc.places.PLACE_TYPE.OPENABLE.HOME_ENTRANCE_DOOR, npc.places.PLACE_TYPE.OPENABLE.HOME_ENTRANCE_DOOR, entrance.node_pos)
 | 
			
		||||
    -- Find the position inside and outside the door
 | 
			
		||||
    local entrance_inside = npc.places.find_node_behind_door(entrance.node_pos)
 | 
			
		||||
    local entrance_outside = npc.places.find_node_in_front_of_door(entrance.node_pos)
 | 
			
		||||
    --minetest.set_node(entrance_inside, {name="default:apple"})
 | 
			
		||||
    -- Assign these places to NPC
 | 
			
		||||
    npc.places.add_public(self, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, entrance_inside)
 | 
			
		||||
    npc.places.add_public(self, npc.places.PLACE_TYPE.OTHER.HOME_OUTSIDE, npc.places.PLACE_TYPE.OTHER.HOME_OUTSIDE, entrance_outside)
 | 
			
		||||
    -- Make NPC go into their house
 | 
			
		||||
    --minetest.log("Place: "..dump(npc.places.get_by_type(self, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE)))
 | 
			
		||||
    npc.add_task(self, npc.actions.cmd.WALK_TO_POS, {end_pos=npc.places.get_by_type(self, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE)[1].pos, walkable={}})  
 | 
			
		||||
    npc.add_action(self, npc.actions.cmd.FREEZE, {freeze = false})
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  local plot_info = minetest.deserialize(meta:get_string("plot_info"))
 | 
			
		||||
@@ -268,10 +273,13 @@ end
 | 
			
		||||
-- point and the building_data to get the x, y and z-coordinate size
 | 
			
		||||
-- of the building schematic
 | 
			
		||||
function spawner.scan_mg_villages_building(pos, building_data)
 | 
			
		||||
  minetest.log("--------------------------------------------")
 | 
			
		||||
  minetest.log("Building data: "..dump(building_data))
 | 
			
		||||
  minetest.log("--------------------------------------------")
 | 
			
		||||
  -- Get area of the building
 | 
			
		||||
  local x_size = building_data.sizex
 | 
			
		||||
  local x_size = building_data.bsizex
 | 
			
		||||
  local y_size = building_data.ysize
 | 
			
		||||
  local z_size = building_data.sizez
 | 
			
		||||
  local z_size = building_data.bsizez
 | 
			
		||||
  local brotate = building_data.brotate
 | 
			
		||||
  local start_pos = {x=pos.x, y=pos.y, z=pos.z}
 | 
			
		||||
  local x_sign, z_sign = 1, 1
 | 
			
		||||
@@ -283,18 +291,30 @@ function spawner.scan_mg_villages_building(pos, building_data)
 | 
			
		||||
  -- 3 - facing South -Z
 | 
			
		||||
  if brotate == 0 then
 | 
			
		||||
    x_sign, z_sign = 1, -1
 | 
			
		||||
  elseif brotate ==1 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
 | 
			
		||||
  elseif brotate == 2 then
 | 
			
		||||
    x_sign, z_sign = -1, 1
 | 
			
		||||
  elseif brotate == 3 then
 | 
			
		||||
    x_sign, z_sign = 1, 1
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  ------------------------
 | 
			
		||||
  -- For debug:
 | 
			
		||||
  ------------------------
 | 
			
		||||
  -- Red is x marker
 | 
			
		||||
  --minetest.set_node({x=pos.x + (x_sign * x_size),y=pos.y,z=pos.z}, {name = "wool:red"})
 | 
			
		||||
  --minetest.get_meta({x=pos.x + (x_sign * x_size),y=pos.y,z=pos.z}):set_string("infotext", minetest.get_meta(pos):get_string("infotext")..", Axis: x, Sign: "..dump(x_sign))
 | 
			
		||||
  -- Blue is z marker
 | 
			
		||||
  --minetest.set_node({x=pos.x,y=pos.y,z=pos.z + (z_sign * z_size)}, {name = "wool:blue"})
 | 
			
		||||
  --minetest.get_meta({x=pos.x,y=pos.y,z=pos.z + (z_sign * z_size)}):set_string("infotext", minetest.get_meta(pos):get_string("infotext")..", Axis: z, Sign: "..dump(z_sign))
 | 
			
		||||
  
 | 
			
		||||
  minetest.log("Start pos: "..minetest.pos_to_string(start_pos))
 | 
			
		||||
  minetest.log("Plot: "..dump(minetest.get_meta(start_pos):get_string("infotext")))
 | 
			
		||||
 | 
			
		||||
  minetest.log("Brotate: "..dump(brotate))
 | 
			
		||||
  minetest.log("X_sign: "..dump(x_sign))
 | 
			
		||||
  minetest.log("X_adj: "..dump(x_sign*x_size))
 | 
			
		||||
@@ -303,6 +323,11 @@ function spawner.scan_mg_villages_building(pos, building_data)
 | 
			
		||||
 | 
			
		||||
  local end_pos = {x=pos.x + (x_sign * x_size), y=pos.y + y_size, z=pos.z + (z_sign * z_size)}
 | 
			
		||||
 | 
			
		||||
  -- For debug:
 | 
			
		||||
  --minetest.set_node(start_pos, {name="default:mese_block"})
 | 
			
		||||
  --minetest.set_node(end_pos, {name="default:mese_block"})
 | 
			
		||||
  --minetest.get_meta(end_pos):set_string("infotext", minetest.get_meta(start_pos):get_string("infotext"))
 | 
			
		||||
 | 
			
		||||
  minetest.log("Calculated end pos: "..minetest.pos_to_string(end_pos))
 | 
			
		||||
 | 
			
		||||
  return spawner.scan_area(start_pos, end_pos)
 | 
			
		||||
@@ -340,11 +365,11 @@ function spawner.replace_mg_villages_plotmarker(pos)
 | 
			
		||||
      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]
 | 
			
		||||
      plot_info["ysize"] = building_data.ysize
 | 
			
		||||
      -- 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)
 | 
			
		||||
      local nodedata = spawner.scan_mg_villages_building(pos, plot_info)
 | 
			
		||||
      -- Store nodedata into the spawner's metadata
 | 
			
		||||
      meta:set_string("node_data", minetest.serialize(nodedata))
 | 
			
		||||
      -- Initialize NPCs
 | 
			
		||||
@@ -405,28 +430,28 @@ if minetest.get_modpath("mg_villages") ~= nil then
 | 
			
		||||
 | 
			
		||||
  -- LBM Registration
 | 
			
		||||
  -- Used to modify plotmarkers and replace them with advanced_npc:plotmarker_auto_spawner
 | 
			
		||||
  minetest.register_lbm({
 | 
			
		||||
    label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners",
 | 
			
		||||
    name = "advanced_npc:mg_villages_plotmarker_replacer",
 | 
			
		||||
    nodenames = {"mg_villages:plotmarker"},
 | 
			
		||||
    run_at_every_load = false,
 | 
			
		||||
    action = function(pos, node)
 | 
			
		||||
      -- Check if replacement is activated
 | 
			
		||||
      if npc.spawner.replace_activated then
 | 
			
		||||
        -- Replace mg_villages:plotmarker
 | 
			
		||||
        spawner.replace_mg_villages_plotmarker(pos)
 | 
			
		||||
        -- Set NPCs to spawn
 | 
			
		||||
        spawner.calculate_npc_spawning(pos)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  })
 | 
			
		||||
  -- minetest.register_lbm({
 | 
			
		||||
  --   label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners",
 | 
			
		||||
  --   name = "advanced_npc:mg_villages_plotmarker_replacer",
 | 
			
		||||
  --   nodenames = {"mg_villages:plotmarker"},
 | 
			
		||||
  --   run_at_every_load = false,
 | 
			
		||||
  --   action = function(pos, node)
 | 
			
		||||
  --     -- Check if replacement is activated
 | 
			
		||||
  --     if npc.spawner.replace_activated then
 | 
			
		||||
  --       -- Replace mg_villages:plotmarker
 | 
			
		||||
  --       spawner.replace_mg_villages_plotmarker(pos)
 | 
			
		||||
  --       -- Set NPCs to spawn
 | 
			
		||||
  --       spawner.calculate_npc_spawning(pos)
 | 
			
		||||
  --     end
 | 
			
		||||
  --   end
 | 
			
		||||
  -- })
 | 
			
		||||
 | 
			
		||||
  -- ABM Registration... for when LBM fails.
 | 
			
		||||
  minetest.register_abm({
 | 
			
		||||
    label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners",
 | 
			
		||||
    nodenames = {"mg_villages:plotmarker"},
 | 
			
		||||
    interval = npc.spawner.replacement_interval,
 | 
			
		||||
    chance = 1,
 | 
			
		||||
    chance = 5,
 | 
			
		||||
    catch_up = true,
 | 
			
		||||
    action = function(pos, node, active_object_count, active_object_count_wider)
 | 
			
		||||
       -- Check if replacement is activated
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user