diff --git a/actions/places.lua b/actions/places.lua index 0954533..1cc787b 100644 --- a/actions/places.lua +++ b/actions/places.lua @@ -22,8 +22,10 @@ npc.places.nodes = { }, SITTABLE_TYPE = { "cottages:bench", + -- Currently commented out since some NPCs + -- were sitting at stairs that are actually staircases -- TODO: Register other stair types - "stairs:stair_wood" + --"stairs:stair_wood" }, STORAGE_TYPE = { "default:chest", @@ -56,7 +58,16 @@ npc.places.PLACE_TYPE = { PRIMARY = "bed_primary" }, SITTABLE = { - PRIMARY = "sit_primary" + PRIMARY = "sit_primary", + SHARED = "sit_shared" + }, + FURNACE = { + PRIMARY = "furnace_primary", + SHARED = "furnace_shared" + }, + STORAGE = { + PRIMARY = "storage_primary", + SHARED = "storage_shared" }, OPENABLE = { HOME_ENTRANCE_DOOR = "home_entrance_door" @@ -68,27 +79,51 @@ npc.places.PLACE_TYPE = { } } -function npc.places.add_public(self, place_name, place_type, pos, access_node) - --minetest.log("Place name: "..dump(place_name)..", type: "..dump(place_type)) +function npc.places.add_shared(self, place_name, place_type, pos, access_node) self.places_map[place_name] = {type=place_type, pos=pos, access_node=access_node or pos, status="shared"} end --- Adds a specific node to the NPC places, and modifies the --- node metadata to identify the NPC as the owner. This allows --- other NPCs to avoid to take this as their own. function npc.places.add_owned(self, place_name, place_type, pos, access_node) - -- Get node metadata - --local meta = minetest.get_meta(pos) - -- Check if it is owned by an NPC? - --if meta:get_string("npc_owner") == "" then - -- Set owned by NPC - --meta:set_string("npc_owner", self.npc_id) - -- Add place to list self.places_map[place_name] = {type=place_type, pos=pos, access_node=access_node or pos, status="owned"} - --npc.places.add_public(self, place_name, place_type, pos) - return true - --end - --return false +end + +function npc.places.add_unowned_accessible_place(self, nodes, place_type) + for i = 1, #nodes do + -- Check if node has owner + if nodes[i].owner == "" then + -- If node has no owner, check if it is accessible + local empty_nodes = npc.places.find_node_orthogonally( + nodes[i].node_pos, {"air"}, 0) + -- Check if node is accessible + if #empty_nodes > 0 then + -- Set owner to this NPC + nodes[i].owner = self.npc_id + -- Assign node to NPC + npc.places.add_owned(self, place_type, place_type, + nodes[i].node_pos, empty_nodes[1].pos) + npc.log("DEBUG", "Added node at "..minetest.pos_to_string(nodes[i].node_pos) + .." to NPC "..dump(self.npc_name)) + break + end + end + end +end + +function npc.places.add_shared_accessible_place(self, nodes, place_type) + for i = 1, #nodes do + -- Check of not adding same owned sit + if nodes[i].owner ~= self.npc_id then + -- Check if it is accessible + local empty_nodes = npc.places.find_node_orthogonally( + nodes[i].node_pos, {"air"}, 0) + -- Check if bed is accessible + if #empty_nodes > 0 then + -- Assign node to NPC + npc.places.add_shared(self, place_type..dump(i), + place_type, nodes[i].node_pos, empty_nodes[1].pos) + end + end + end end function npc.places.get_by_type(self, place_type) diff --git a/npc.lua b/npc.lua index 9e230e8..56fbd24 100755 --- a/npc.lua +++ b/npc.lua @@ -44,7 +44,7 @@ npc.action_state = { npc.log_level = { INFO = true, - WARNING = false, + WARNING = true, ERROR = true, DEBUG = false } @@ -884,6 +884,11 @@ mobs:register_mob("advanced_npc:npc", { drawtype = "front", textures = { {"npc_male1.png"}, + {"npc_male2.png"}, + {"npc_male3.png"}, + {"npc_male4.png"}, + {"npc_male5.png"}, + {"npc_male6.png"}, {"npc_female1.png"}, -- female by nuttmeg20 }, child_texture = { @@ -938,7 +943,7 @@ mobs:register_mob("advanced_npc:npc", { --self.textures = {"mobs_npc_child_male1.png"} --self.base_texture = "mobs_npc_child_male1.png" --self.object:set_properties(self) - + npc.log("INFO", "NPC places: "..dump(self.places_map)) npc.log("DEBUG", "Right-clicked NPC: "..dump(self)) -- Receive gift or start chat. If player has no item in hand @@ -980,10 +985,14 @@ mobs:register_mob("advanced_npc:npc", { -- NPC is initialized, check other variables -- Check child texture issues if self.is_child then + -- Check texture npc.texture_check.timer = npc.texture_check.timer + dtime if npc.texture_check.timer > npc.texture_check.interval then -- Reset timer npc.texture_check.timer = 0 + -- Set hornytimer to zero every 60 seconds so that children + -- don't grow automatically + self.hornytimer = 0 -- Set correct textures self.texture = {self.selected_texture} self.base_texture = {self.selected_texture} diff --git a/spawner.lua b/spawner.lua index 032481c..c883eb5 100644 --- a/spawner.lua +++ b/spawner.lua @@ -88,9 +88,38 @@ local function get_basic_schedule() -- Allow mobs_redo wandering [3] = {action = npc.actions.cmd.FREEZE, args = {freeze = false}} }, + -- Noon actions: go inside the house + -- This will be executed around 12 PM MTG time + noon_actions = { + -- Walk to a sittable node + [1] = {task = npc.actions.cmd.WALK_TO_POS, args = { + end_pos = {place_type=npc.places.PLACE_TYPE.SITTABLE.PRIMARY, use_access_node=true}, + walkable = {"cottages:bench"} + } + }, + -- Sit on the node + [2] = {task = npc.actions.cmd.USE_SITTABLE, args = { + pos = npc.places.PLACE_TYPE.SITTABLE.PRIMARY, + action = npc.actions.const.sittable.SIT + } + }, + -- Stay put into place + [3] = {action = npc.actions.cmd.FREEZE, args = {freeze = true}} + }, + -- Afternoon actions: go inside the house + -- This will be executed around 1 PM MTG time + afternoon_actions = { + [1] = {task = npc.actions.cmd.USE_SITTABLE, args = { + pos = npc.places.PLACE_TYPE.SITTABLE.PRIMARY, + action = npc.actions.const.sittable.GET_UP + } + }, + -- Allow mobs_redo wandering + [2] = {action = npc.actions.cmd.FREEZE, args = {freeze = false}} + }, -- Afternoon actions: go inside the house -- This will be executed around 6 PM MTG time - afternoon_actions = { + late_afternoon_actions = { -- Get inside home [1] = {task = npc.actions.cmd.WALK_TO_POS, args = { end_pos = npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, @@ -164,6 +193,7 @@ function spawner.scan_area(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) + -- Filter out result.furnace_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.FURNACE_TYPE) result.storage_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.STORAGE_TYPE) result.openable_type = spawner.get_nodes_by_type(start_pos, end_pos, npc.places.nodes.OPENABLE_TYPE) @@ -190,49 +220,77 @@ function spawner.assign_places(self, pos) local node_data = minetest.deserialize(meta:get_string("node_data")) -- Assign plotmarker - npc.places.add_public(self, npc.places.PLACE_TYPE.OTHER.HOME_PLOTMARKER, + npc.places.add_shared(self, npc.places.PLACE_TYPE.OTHER.HOME_PLOTMARKER, npc.places.PLACE_TYPE.OTHER.HOME_PLOTMARKER, pos) -- Assign entrance door and related locations if entrance ~= nil and entrance.node_pos ~= nil then - npc.places.add_public(self, npc.places.PLACE_TYPE.OPENABLE.HOME_ENTRANCE_DOOR, npc.places.PLACE_TYPE.OPENABLE.HOME_ENTRANCE_DOOR, entrance.node_pos) + npc.places.add_shared(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) -- 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) + npc.places.add_shared(self, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, npc.places.PLACE_TYPE.OTHER.HOME_INSIDE, entrance_inside) + npc.places.add_shared(self, npc.places.PLACE_TYPE.OTHER.HOME_OUTSIDE, npc.places.PLACE_TYPE.OTHER.HOME_OUTSIDE, entrance_outside) end -- Assign beds if #node_data.bed_type > 0 then - -- Find unowned bed - for i = 1, #node_data.bed_type do - -- Check if bed has owner - --minetest.log("Node: "..dump(node_data.bed_type[i])) - if node_data.bed_type[i].owner == "" then - -- If bed has no owner, check if it is accessible - local empty_nodes = npc.places.find_node_orthogonally( - node_data.bed_type[i].node_pos, {"air"}, 0) - -- Check if bed is accessible - if #empty_nodes > 0 then - -- Set owner to this NPC - node_data.bed_type[i].owner = self.npc_id - -- Assign node to NPC - npc.places.add_owned(self, npc.places.PLACE_TYPE.BED.PRIMARY, - npc.places.PLACE_TYPE.BED.PRIMARY, node_data.bed_type[i].node_pos, empty_nodes[1].pos) - -- Store changes to node_data - meta:set_string("node_data", minetest.serialize(node_data)) - npc.log("DEBUG", "Added bed at "..minetest.pos_to_string(node_data.bed_type[i].node_pos) - .." to NPC "..dump(self.npc_name)) - break - end - end - end + -- Assign a specific sittable node to a NPC. + npc.places.add_unowned_accessible_place(self, node_data.bed_type, + npc.places.PLACE_TYPE.BED.PRIMARY) + -- Store changes to node_data + meta:set_string("node_data", minetest.serialize(node_data)) + end + + -- Assign sits + if #node_data.sittable_type > 0 then + -- Check if there are same or more amount of sits as beds + if #node_data.sittable_type >= #node_data.bed_type then + -- Assign a specific sittable node to a NPC. + npc.places.add_unowned_accessible_place(self, node_data.sittable_type, + npc.places.PLACE_TYPE.SITTABLE.PRIMARY) + -- Store changes to node_data + meta:set_string("node_data", minetest.serialize(node_data)) + end + -- Add all sits to places as shared since NPC should be able to sit + -- at any accessible sit + npc.places.add_shared_accessible_place(self, node_data.sittable_type, + npc.places.PLACE_TYPE.SITTABLE.SHARED) + end + + -- Assign furnaces + if #node_data.furnace_type > 0 then + -- Check if there are same or more amount of furnace as beds + if #node_data.furnace_type >= #node_data.bed_type then + -- Assign a specific furnace node to a NPC. + npc.places.add_unowned_accessible_place(self, node_data.furnace_type, + npc.places.PLACE_TYPE.FURNACE.PRIMARY) + -- Store changes to node_data + meta:set_string("node_data", minetest.serialize(node_data)) + end + -- Add all furnaces to places as shared since NPC should be able to use + -- any accessible furnace + npc.places.add_shared_accessible_place(self, node_data.furnace_type, + npc.places.PLACE_TYPE.FURNACE.SHARED) + end + + -- Assign storage nodes + if #node_data.storage_type > 0 then + -- Check if there are same or more amount of storage as beds + if #node_data.storage_type >= #node_data.bed_type then + -- Assign a specific storage node to a NPC. + npc.places.add_unowned_accessible_place(self, node_data.storage_type, + npc.places.PLACE_TYPE.STORAGE.PRIMARY) + -- Store changes to node_data + meta:set_string("node_data", minetest.serialize(node_data)) + end + -- Add all storage-types to places as shared since NPC should be able + -- to use other storage nodes as well. + npc.places.add_shared_accessible_place(self, node_data.storage_type, + npc.places.PLACE_TYPE.STORAGE.SHARED) end - --local plot_info = minetest.deserialize(meta:get_string("plot_info")) - --minetest.log("Plot info:"..dump(plot_info)) npc.log("DEBUG", "Places for NPC "..self.npc_name..": "..dump(self.places_map)) -- Make NPC go into their house @@ -253,8 +311,14 @@ function spawner.assign_schedules(self, pos) -- Add schedule entry for morning actions npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 8, nil, basic_schedule.morning_actions) + -- Add schedule entry for noon actions + npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 12, nil, basic_schedule.noon_actions) + -- Add schedule entry for afternoon actions - npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 18, nil, basic_schedule.afternoon_actions) + npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 13, nil, basic_schedule.afternoon_actions) + + -- Add schedule entry for late afternoon actions + npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 18, nil, basic_schedule.late_afternoon_actions) -- Add schedule entry for evening actions npc.add_schedule_entry(self, npc.schedule_types.generic, 0, 22, nil, basic_schedule.evening_actions) @@ -620,8 +684,8 @@ if minetest.get_modpath("mg_villages") ~= nil then minetest.register_abm({ label = "Replace mg_villages:plotmarker with Advanced NPC auto spawners", nodenames = {"mg_villages:plotmarker"}, - interval = npc.spawner.replacement_interval, - chance = 5, + interval = 10,--npc.spawner.replacement_interval, + chance = 1,--5, catch_up = true, action = function(pos, node, active_object_count, active_object_count_wider) -- Check if replacement is needed