From d4e8744cfb1b95089069bf3dd0de274b65cf02e0 Mon Sep 17 00:00:00 2001 From: Hector Franqui Date: Fri, 19 May 2017 14:36:11 -0400 Subject: [PATCH] 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. --- actions/actions.lua | 8 ++--- actions/pathfinder.lua | 10 ++++-- actions/places.lua | 25 +++++++++++--- npc.lua | 4 +-- spawner.lua | 75 ++++++++++++++++++++++++++++-------------- 5 files changed, 84 insertions(+), 38 deletions(-) diff --git a/actions/actions.lua b/actions/actions.lua index c36cf21..39d9e30 100644 --- a/actions/actions.lua +++ b/actions/actions.lua @@ -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 diff --git a/actions/pathfinder.lua b/actions/pathfinder.lua index 9e47325..d0d604f 100644 --- a/actions/pathfinder.lua +++ b/actions/pathfinder.lua @@ -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)}) diff --git a/actions/places.lua b/actions/places.lua index 51d53ba..8f0a5c6 100644 --- a/actions/places.lua +++ b/actions/places.lua @@ -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 \ No newline at end of file diff --git a/npc.lua b/npc.lua index 05d9dcd..2efad1a 100755 --- a/npc.lua +++ b/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) diff --git a/spawner.lua b/spawner.lua index d69e397..a283efc 100644 --- a/spawner.lua +++ b/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