Places: Allow finding alternative nodes when nodes are being used.

Add owned and used properties to each owned/shared node.
Actions: Allow to find alternative sittable/bed/furnace node if currently
being used.
Default occupation: Add alternative sitting finding.
NPC: Log cleanup.
This commit is contained in:
Hector Franqui 2017-10-05 18:53:46 -04:00
parent d92b729e19
commit 8a5e80e2cb
4 changed files with 185 additions and 20 deletions

View File

@ -664,19 +664,42 @@ local function get_pos_argument(self, pos, use_access_node)
return pos return pos
elseif pos.place_type ~= nil then elseif pos.place_type ~= nil then
-- Received table in the following format: -- Received table in the following format:
-- {place_type = "", index = 1, use_access_node = false} -- {
-- place_category = "",
-- place_type = "",
-- index = 1,
-- use_access_node = false|true,
-- try_alternative_if_used = true|false
-- }
local index = pos.index or 1 local index = pos.index or 1
local use_access_node = pos.use_access_node or false local use_access_node = pos.use_access_node or false
local try_alternative_if_used = pos.try_alternative_if_used or false
local places = npc.places.get_by_type(self, pos.place_type) local places = npc.places.get_by_type(self, pos.place_type)
--minetest.log("Place type: "..dump(pos.place_type))
--minetest.log("Places: "..dump(places))
-- Check index is valid on the places map -- Check index is valid on the places map
if #places >= index then if #places >= index then
local place = places[index]
-- Check if place is used, and if it is, find alternative if required
if try_alternative_if_used == true then
place = npc.places.find_unused_place(self, pos.place_category, pos.place_type, place)
--minetest.log("Mark as used? "..dump(pos.mark_target_as_used))
if pos.mark_target_as_used == true then
--minetest.log("Marking as used: "..minetest.pos_to_string(place.pos))
npc.places.mark_place_used(place.pos, npc.places.USE_STATE.USED)
end
npc.places.add_shared_accessible_place(
self, {owner="", node_pos=place.pos}, npc.places.PLACE_TYPE.CALCULATED.TARGET, true, {})
end
-- Check if access node is desired -- Check if access node is desired
if use_access_node == true then if use_access_node == true then
-- Return actual node pos -- Return actual node pos
return places[index].access_node, places[index].pos return place.access_node, place.pos
else else
-- Return node pos that allows access to node -- Return node pos that allows access to node
return places[index].pos return place.pos
end end
end end
end end
@ -722,6 +745,7 @@ function npc.actions.use_furnace(self, args)
return return
end end
local enable_usage_marking = args.enable_usage_marking or true
local item = args.item local item = args.item
local freeze = args.freeze local freeze = args.freeze
-- Define which items are usable as fuels. The NPC -- Define which items are usable as fuels. The NPC
@ -775,6 +799,12 @@ function npc.actions.use_furnace(self, args)
return cook_result.time - fuel_time return cook_result.time - fuel_time
end end
-- Set furnace as used if flag is enabled
if enable_usage_marking then
-- Set place as used
npc.places.mark_place_used(pos, npc.places.USE_STATE.USED)
end
-- Calculate how much fuel is needed -- Calculate how much fuel is needed
local fuel_amount = total_cook_time / fuel_time local fuel_amount = total_cook_time / fuel_time
if fuel_amount < 1 then if fuel_amount < 1 then
@ -832,6 +862,12 @@ function npc.actions.use_furnace(self, args)
npc.log("DEBUG", "Inventory: "..dump(self.inventory)) npc.log("DEBUG", "Inventory: "..dump(self.inventory))
-- Set furnace as unused if flag is enabled
if enable_usage_marking then
-- Set place as used
npc.places.mark_place_used(pos, npc.places.USE_STATE.NOT_USED)
end
return true return true
end end
end end
@ -848,6 +884,7 @@ function npc.actions.use_bed(self, args)
return return
end end
local action = args.action local action = args.action
local enable_usage_marking = args.enable_usage_marking or true
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
--minetest.log(dump(node)) --minetest.log(dump(node))
local dir = minetest.facedir_to_dir(node.param2) local dir = minetest.facedir_to_dir(node.param2)
@ -863,6 +900,10 @@ function npc.actions.use_bed(self, args)
npc.add_action(self, npc.actions.cmd.SIT, {pos=bed_pos, dir=(node.param2 + 2) % 4}) npc.add_action(self, npc.actions.cmd.SIT, {pos=bed_pos, dir=(node.param2 + 2) % 4})
-- Lay down -- Lay down
npc.add_action(self, npc.actions.cmd.LAY, {}) npc.add_action(self, npc.actions.cmd.LAY, {})
if enable_usage_marking then
-- Set place as used
npc.places.mark_place_used(pos, npc.places.USE_STATE.USED)
end
else else
-- Calculate position to get up -- Calculate position to get up
-- Error here due to ignore. Need to come up with better solution -- Error here due to ignore. Need to come up with better solution
@ -906,9 +947,12 @@ function npc.actions.use_bed(self, args)
end end
end end
-- Stand out of bed -- Stand out of bed
npc.add_action(self, npc.actions.cmd.STAND, {pos=pos_out_of_bed, dir=dir}) npc.add_action(self, npc.actions.cmd.STAND, {pos=pos_out_of_bed, dir=dir})
if enable_usage_marking then
-- Set place as unused
npc.places.mark_place_used(pos, npc.places.USE_STATE.NOT_USED)
end
end end
end end
@ -921,6 +965,7 @@ function npc.actions.use_sittable(self, args)
return return
end end
local action = args.action local action = args.action
local enable_usage_marking = args.enable_usage_marking or true
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
if action == npc.actions.const.sittable.SIT then if action == npc.actions.const.sittable.SIT then
@ -932,6 +977,10 @@ function npc.actions.use_sittable(self, args)
local sit_pos = npc.actions.nodes.sittable[node.name].get_sit_pos(pos, node.param2) local sit_pos = npc.actions.nodes.sittable[node.name].get_sit_pos(pos, node.param2)
-- Sit down on bench/chair/stairs -- Sit down on bench/chair/stairs
npc.add_action(self, npc.actions.cmd.SIT, {pos=sit_pos, dir=(node.param2 + 2) % 4}) npc.add_action(self, npc.actions.cmd.SIT, {pos=sit_pos, dir=(node.param2 + 2) % 4})
if enable_usage_marking then
-- Set place as used
npc.places.mark_place_used(pos, npc.places.USE_STATE.USED)
end
else else
-- Find empty areas around chair -- Find empty areas around chair
local dir = node.param2 + 2 % 4 local dir = node.param2 + 2 % 4
@ -951,6 +1000,11 @@ function npc.actions.use_sittable(self, args)
end end
-- Stand -- Stand
npc.add_action(self, npc.actions.cmd.STAND, {pos=pos_out_of_sittable, dir=dir}) npc.add_action(self, npc.actions.cmd.STAND, {pos=pos_out_of_sittable, dir=dir})
minetest.log("Setting sittable at "..minetest.pos_to_string(pos).." as not used")
if enable_usage_marking then
-- Set place as unused
npc.places.mark_place_used(pos, npc.places.USE_STATE.NOT_USED)
end
end end
end end

View File

@ -63,6 +63,17 @@ npc.places.nodes = {
npc.places.PLACE_TYPE = { npc.places.PLACE_TYPE = {
CATEGORIES = {
BED = "BED",
SITTABLE = "SITTABLE",
FURNACE = "FURNACE",
STORAGE = "STORAGE",
OPENABLE = "OPENABLE",
SCHEDULE = "SCHEDULE",
CALCULATED = "CALCULATED",
WORKPLACE = "WORKPLACE",
OTHER = "OTHER"
},
BED = { BED = {
PRIMARY = "bed_primary" PRIMARY = "bed_primary"
}, },
@ -84,6 +95,9 @@ npc.places.PLACE_TYPE = {
SCHEDULE = { SCHEDULE = {
TARGET = "schedule_target_pos" TARGET = "schedule_target_pos"
}, },
CALCULATED = {
TARGET = "calculated_target_pos"
},
WORKPLACE = { WORKPLACE = {
PRIMARY = "workplace_primary", PRIMARY = "workplace_primary",
TOOL = "workplace_tool" TOOL = "workplace_tool"
@ -92,14 +106,60 @@ npc.places.PLACE_TYPE = {
HOME_PLOTMARKER = "home_plotmarker", HOME_PLOTMARKER = "home_plotmarker",
HOME_INSIDE = "home_inside", HOME_INSIDE = "home_inside",
HOME_OUTSIDE = "home_outside" HOME_OUTSIDE = "home_outside"
},
is_primary = function(place_type)
local p1,p2 = string.find(place_type, "primary")
return p1 ~= nil
end,
-- Only works for place types where there is a "primary" and a "shared"
get_alternative = function(place_category, place_type)
local result = {}
local place_types = npc.places.PLACE_TYPE[place_category]
-- Determine search type
local search_shared = false
if npc.places.PLACE_TYPE.is_primary(place_type) then
search_shared = true
end
for key,place_type in pairs(place_types) do
if search_shared == true then
if npc.places.PLACE_TYPE.is_primary(place_type) == false then
return place_type
end
else
if npc.places.PLACE_TYPE.is_primary(place_type) == true then
return place_type
end
end
end
end
} }
npc.places.USE_STATE = {
USED = "true",
NOT_USED = "false"
} }
function npc.places.add_shared(self, place_name, place_type, pos, access_node) function npc.places.add_shared(self, place_name, place_type, pos, access_node)
-- Set metadata of node
local meta = minetest.get_meta(pos)
if not meta:get_string("advanced_npc:used") then
meta:set_string("advanced_npc:used", npc.places.USE_STATE.NOT_USED)
end
meta:set_string("advanced_npc:owner", "")
-- This avoid lags
meta:mark_as_private({"advanced_npc:used", "advanced_npc:owner"})
self.places_map[place_name] = {type=place_type, pos=pos, access_node=access_node or pos, status="shared"} self.places_map[place_name] = {type=place_type, pos=pos, access_node=access_node or pos, status="shared"}
end end
function npc.places.add_owned(self, place_name, place_type, pos, access_node) function npc.places.add_owned(self, place_name, place_type, pos, access_node)
-- Set metadata of node
local meta = minetest.get_meta(pos)
if not meta:get_string("advanced_npc:used") then
meta:set_string("advanced_npc:used", npc.places.USE_STATE.NOT_USED)
end
meta:set_string("advanced_npc:owner", self.npc_id)
-- This avoid lags
meta:mark_as_private({"advanced_npc:used", "advanced_npc:owner"})
self.places_map[place_name] = {type=place_type, pos=pos, access_node=access_node or pos, status="owned"} self.places_map[place_name] = {type=place_type, pos=pos, access_node=access_node or pos, status="owned"}
end end
@ -161,6 +221,48 @@ function npc.places.add_shared_accessible_place(self, nodes, place_type, overrid
end end
end end
function npc.places.mark_place_used(pos, value)
local meta = minetest.get_meta(pos)
local used = meta:get_string("advanced_npc:used")
if value == used then
npc.log("WARNING", "Attempted to set 'used' property of node at "
..minetest.pos_to_string(pos).." to the same value: '"..dump(value).."'")
return false
else
meta:set_string("advanced_npc:used", value)
npc.log("DEBUG", "'Used' value at pos "..minetest.pos_to_string(pos)..": "..dump(meta:get_string("advanced_npc:used")))
return true
end
end
-- This function is to find an alternative place if the original is
-- not usable. If the original place is a "primary" place, it will
-- try to find a "shared" place. If it is a "shared" place, it will try
-- to find a "primary" place. If none is found, it retuns the given type.
function npc.places.find_unused_place(self, place_category, place_type, original_place)
local result = {}
-- Check if node is being used
local meta = minetest.get_meta(original_place.pos)
local used = meta:get_string("advanced_npc:used")
if used == npc.places.USE_STATE.USED then
-- Node is being used, try to find alternative
local alternative_place_type = npc.places.PLACE_TYPE.get_alternative(place_category, place_type)
--minetest.log("Alternative place type: "..dump(alternative_place_type))
local alternative_places = npc.places.get_by_type(self, alternative_place_type)
--minetest.log("Alternatives: "..dump(alternative_places))
for i = 1, #alternative_places do
meta = minetest.get_meta(alternative_places[i].pos)
local used = meta:get_string("advanced_npc:used")
if used == npc.places.USE_STATE.NOT_USED then
return alternative_places[i]
end
end
else
result = original_place
end
return result
end
function npc.places.get_by_type(self, place_type, exact_match) function npc.places.get_by_type(self, place_type, exact_match)
local result = {} local result = {}
for _, place_entry in pairs(self.places_map) do for _, place_entry in pairs(self.places_map) do

View File

@ -55,15 +55,23 @@ local basic_def = {
-- Schedule entry for 12 midday -- Schedule entry for 12 midday
[12] = { [12] = {
-- Walk to a sittable node -- Walk to a sittable node
[1] = {task = npc.actions.cmd.WALK_TO_POS, args = { [1] = {task = npc.actions.cmd.WALK_TO_POS,
end_pos = {place_type=npc.places.PLACE_TYPE.SITTABLE.PRIMARY, use_access_node=true}, args = {
end_pos = {
place_category=npc.places.PLACE_TYPE.CATEGORIES.SITTABLE,
place_type=npc.places.PLACE_TYPE.SITTABLE.PRIMARY,
use_access_node=true,
try_alternative_if_used=true,
mark_target_as_used = true
},
walkable = {"cottages:bench"} walkable = {"cottages:bench"}
}, },
chance = 75 chance = 75
}, },
-- Sit on the node -- Sit on the node
[2] = {task = npc.actions.cmd.USE_SITTABLE, args = { [2] = {task = npc.actions.cmd.USE_SITTABLE,
pos = npc.places.PLACE_TYPE.SITTABLE.PRIMARY, args = {
pos = npc.places.PLACE_TYPE.CALCULATED.TARGET,
action = npc.actions.const.sittable.SIT action = npc.actions.const.sittable.SIT
}, },
depends = {1} depends = {1}
@ -83,10 +91,10 @@ local basic_def = {
}, },
-- Get up from sit -- Get up from sit
[5] = {action = npc.actions.cmd.USE_SITTABLE, args = { [5] = {action = npc.actions.cmd.USE_SITTABLE, args = {
pos = npc.places.PLACE_TYPE.SITTABLE.PRIMARY, pos = npc.places.PLACE_TYPE.CALCULATED.TARGET,
action = npc.actions.const.sittable.GET_UP action = npc.actions.const.sittable.GET_UP
}, },
depends = {4} --depends = {4}
} }
}, },
-- Schedule entry for 1 in the afternoon -- Schedule entry for 1 in the afternoon
@ -142,7 +150,8 @@ local basic_def = {
} }
}, },
-- Use bed -- Use bed
[2] = {task = npc.actions.cmd.USE_BED, args = { [2] = {task = npc.actions.cmd.USE_BED,
args = {
pos = npc.places.PLACE_TYPE.BED.PRIMARY, pos = npc.places.PLACE_TYPE.BED.PRIMARY,
action = npc.actions.const.beds.LAY action = npc.actions.const.beds.LAY
} }

View File

@ -564,7 +564,7 @@ function npc.generate_trade_list_from_inventory(self)
end end
function npc.set_trading_status(self, status) function npc.set_trading_status(self, status)
minetest.log("Trader_data: "..dump(self.trader_data)) --minetest.log("Trader_data: "..dump(self.trader_data))
-- Set status -- Set status
self.trader_data.trader_status = status self.trader_data.trader_status = status
-- Re-generate trade offers -- Re-generate trade offers