255 lines
9.9 KiB
Lua
255 lines
9.9 KiB
Lua
|
|
-- helper function for mg_villages.analyze_building_for_mobs_update_paths
|
|
-- "res" is the raw data as provided by analyze_file
|
|
-- "node_name" is the name of the node we are looking for
|
|
mg_villages.analyze_building_for_mobs_search_nodes = function( res, node_name, check_place_for_standing )
|
|
local node_positions = {};
|
|
-- find out if the building contains any of the nodes we are looking for
|
|
local found = -1;
|
|
for i,n in ipairs( res.nodenames ) do
|
|
if( n == node_name ) then
|
|
found = i;
|
|
end
|
|
end
|
|
-- that node does not exist in the building
|
|
if( found == -1 ) then
|
|
return {};
|
|
end
|
|
|
|
for z = 1, res.size.z do
|
|
for y = 1, res.size.y do
|
|
for x = 1, res.size.x do
|
|
if( res.scm_data_cache[y]
|
|
and res.scm_data_cache[y][x]
|
|
and res.scm_data_cache[y][x][z]
|
|
and res.scm_data_cache[y][x][z][1] == found ) then
|
|
|
|
if( (check_place_for_standing==false)
|
|
) then
|
|
-- or ( mob_world_interaction.can_stand_in_node_type( TODO )
|
|
-- and mob_world_interaction.can_stand_in_node_type( TODO ))) then
|
|
table.insert( node_positions, {x=x, y=y, z=z, p2=res.scm_data_cache[y][x][z][2]});
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return node_positions;
|
|
end
|
|
|
|
|
|
|
|
|
|
-- changes path_info and adds paths from beds and workplaces to front of building
|
|
-- path_info[ short_file_name ] contains the paths from the beds
|
|
-- path_info[ short_file_name.."|WORKPLACE" ] contains the paths from the workplaces
|
|
-- creates building_data.all_entrances
|
|
-- creates building_data.workplace_list
|
|
mg_villages.analyze_building_for_mobs_update_paths = function( file_name, building_data, path_info )
|
|
|
|
local short_file_name = string.sub(file_name, mg_villages.file_name_offset, 256);
|
|
building_data.short_file_name = short_file_name;
|
|
|
|
if( not( minetest.get_modpath( "mob_world_interaction" ))) then
|
|
return building_data;
|
|
end
|
|
|
|
-- identify front doors and paths to them from the beds
|
|
-- TODO: provide a more general list with beds, work places etc.
|
|
if( building_data.bed_list
|
|
and #building_data.bed_list > 0 ) then
|
|
if(not( path_info[ short_file_name ])) then
|
|
print("BEDS in "..tostring( short_file_name )..":");
|
|
path_info[ short_file_name ] = mob_world_interaction.find_all_front_doors( building_data, building_data.bed_list );
|
|
end
|
|
-- we are looking for the places in front of the front doors; not the front doors themshelves
|
|
building_data.all_entrances = {};
|
|
for i,e in ipairs( path_info[ short_file_name ] ) do
|
|
-- the last entry in the list for the first bed is what we are looking for
|
|
-- (provided there actually is a path)
|
|
if( e[1] and #e[1]>0 ) then
|
|
table.insert( building_data.all_entrances, e[1][ #e[1] ]);
|
|
end
|
|
end
|
|
end
|
|
|
|
-- some buildings (i.e. a tavern, school, shop, church, ...) contain places where a mob working
|
|
-- there will most likely be standing, awaiting his guests/doing his job. Such places can be
|
|
-- manually marked by placing mg_villages:mob_workplace_marker
|
|
|
|
-- this is diffrent information from the normal bed list
|
|
local store_as = short_file_name.."|WORKPLACE";
|
|
if(not( path_info[ store_as ] )) then
|
|
local workplace_list = mg_villages.analyze_building_for_mobs_search_nodes( building_data, "mg_villages:mob_workplace_marker", false );
|
|
|
|
if( workplace_list and #workplace_list>0) then
|
|
-- store it for later use
|
|
building_data.workplace_list = workplace_list;
|
|
|
|
print("WORKPLACE: "..tostring( building_data.short_file_name )..": "..minetest.serialize( workplace_list ));
|
|
path_info[ store_as ] = mob_world_interaction.find_all_front_doors( building_data, workplace_list );
|
|
|
|
-- if no entrances are known yet, then store them now; the entrances associated with
|
|
-- beds are considered to be more important. This here is only a fallback if no beds
|
|
-- exist in the house.
|
|
if( not( building_data.all_entrances )) then
|
|
-- we are looking for the places in front of the front doors; not the front doors themshelves
|
|
building_data.all_entrances = {};
|
|
for i,e in ipairs( path_info[ store_as ] ) do
|
|
-- might just be the place outside the house instead of a door
|
|
if( e[1] and #e[1]>0 ) then
|
|
table.insert( building_data.all_entrances, e[1][ #e[1] ]);
|
|
end
|
|
end
|
|
end
|
|
-- else
|
|
-- print("NO workplace found in "..tostring(building_data.short_file_name ));
|
|
end
|
|
end
|
|
|
|
--[[
|
|
TODO: check if 2 nodes above the target node are air or walkable;
|
|
TODO: exceptions to that: bench (only 1 above needs to be walkable)
|
|
TODO: other exceptions: furnace, chests, washing place: place in front is wanted - not on top
|
|
TODO: search for:
|
|
local pos_list = mg_villages.analyze_building_for_mobs_search_nodes( building_data, "farming:soil_wet", true );
|
|
farming:soil farming:soil_wet
|
|
cottages:straw_ground
|
|
default:chest cottages:shelf cottages:chest_storage cottages:chest_private cottages:chest_work
|
|
cottages:bench (cottages:table?)
|
|
cottages:washing
|
|
default:furnace
|
|
cottages:barrel (and variants); cottages:tub
|
|
|
|
default:ladder
|
|
default:fence_wood cottages:gate_closed cottages:gate_open
|
|
any door...
|
|
any hatch...
|
|
--]]
|
|
|
|
-- some debug information
|
|
if( mg_villages.DEBUG_LEVEL and mg_villages.DEBUG_LEVEL == mg_villages.DEBUG_LEVEL_TIMING ) then
|
|
local str2 = " in "..short_file_name.." ["..building_data.typ.."]";
|
|
if( not( path_info[ short_file_name ] )
|
|
and not( path_info[ store_as ] )) then
|
|
str2 = "nothing of intrest (no bed, no workplace)"..str2;
|
|
elseif( path_info[ short_file_name ]
|
|
and (#path_info[ short_file_name ]<1
|
|
or #path_info[ short_file_name ][1]<1
|
|
or #path_info[ short_file_name ][1][1]<1 )) then
|
|
str2 = "BROKEN paths for beds"..str2;
|
|
elseif( path_info[ store_as ]
|
|
and (#path_info[ store_as ]<1
|
|
or #path_info[ store_as ][1]<1
|
|
or #path_info[ store_as ][1][1]<1 )) then
|
|
str2 = "BROKEN paths for workplaces"..str2;
|
|
else
|
|
if( path_info[ store_as ] ) then
|
|
str2 = tostring( #path_info[ store_as ][1]-1 )..
|
|
" workplaces"..str2;
|
|
else
|
|
str2 = "no workplaces"..str2;
|
|
end
|
|
if( path_info[ short_file_name ] ) then
|
|
str2 = tostring( #path_info[ short_file_name ][1]-1 )..
|
|
" beds and "..str2;
|
|
else
|
|
str2 = "no beds and "..str2;
|
|
end
|
|
end
|
|
print( str2 );
|
|
end
|
|
return building_data;
|
|
end
|
|
|
|
|
|
|
|
-- Calls mg_villages.analyze_building_for_mobs_update_paths and evaluates the output:
|
|
-- * determines the position of front doors (building_data.front_door_list)
|
|
-- * position of beds (building_data.bed_list)
|
|
-- * places where mobs can stand when they got up from their bed or want
|
|
-- to go to bed (building_data.stand_next_to_bed_list)
|
|
-- * amount of usable beds in the house (building_data.bed_count)
|
|
-- * position of workplaces where a currently working mob may want to
|
|
-- stand (i.e. behind a shop's counter, next to a machine, in front
|
|
-- of the class/congregation, ..) (building_data.workplace_list)
|
|
-- Returns: Updated building_data with the values mentionned above set.
|
|
-- building_data Information about the building as gained from registration
|
|
-- and from handle_schematics.analze_file(..)
|
|
-- file_name with complete path to the schematic
|
|
-- path_info Data structure where path_info (paths from doors to beds etc.)
|
|
-- is cached.
|
|
mg_villages.analyze_building_for_mobs = function( building_data, file_name, path_info )
|
|
|
|
-- identify front doors, calculate paths from beds/workplaces to front of house
|
|
building_data = mg_villages.analyze_building_for_mobs_update_paths( file_name, building_data, path_info );
|
|
|
|
-- building_data.bed_list and building_data.workspace_list are calculated withhin
|
|
-- the above function - provided they are not part of path_info yet;
|
|
-- the information stored in path_info is the relevant one for mob movement/pathfinding
|
|
|
|
-- store the front doors in extra list
|
|
building_data.front_door_list = {};
|
|
-- gain the list of beds from path_info data
|
|
building_data.bed_list = {};
|
|
-- mobs are seldom able to stand directly on or even next to the bed when getting up
|
|
building_data.stand_next_to_bed_list = {};
|
|
-- have any beds been found?
|
|
if( building_data.short_file_name
|
|
and path_info[ building_data.short_file_name ] ) then
|
|
local paths = path_info[ building_data.short_file_name];
|
|
if( paths and paths[1] ) then
|
|
-- iterate over all bed-to-first-front-door-paths (we want to identify beds)
|
|
for i,p in ipairs( paths[1] ) do
|
|
-- the last entry has a diffrent meaning
|
|
if( p and p[1] and i<#paths[1]) then
|
|
-- param2 is the 5th parameter
|
|
building_data.bed_list[i] = {p[1][1],p[1][2],p[1][3],p[1][5]};
|
|
-- also store where the mob may stand
|
|
if( p[2] ) then
|
|
building_data.stand_next_to_bed_list[i] = p[2];
|
|
end
|
|
end
|
|
end
|
|
-- iterate over all paths and take a look at the first bed only (we want to
|
|
-- get the doors now, not the beds)
|
|
for i,p in ipairs( paths ) do
|
|
-- paths[i]: paths from all beds to front door i
|
|
-- paths[i][1]: path from first bed to front door i
|
|
if( p and p[1] ) then
|
|
-- the place in front of the door is the last entry
|
|
local d = p[1][ #p[1] ];
|
|
building_data.front_door_list[i] = {d[1],d[2],d[3]};
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- make sure this refers to the same data as building_data.bed_list
|
|
building_data.bed_count = #building_data.bed_list;
|
|
|
|
-- gain the list of workplaces from the path_info data
|
|
building_data.workplace_list = {};
|
|
-- have any workplaces been found?
|
|
if( building_data.short_file_name
|
|
and path_info[ building_data.short_file_name.."|WORKPLACE" ] ) then
|
|
local paths = path_info[ building_data.short_file_name.."|WORKPLACE"];
|
|
if( paths and paths[1] ) then
|
|
for i,p in ipairs( paths[1] ) do
|
|
if( p and p[1] and i<#paths[1]) then
|
|
building_data.workplace_list[i] = {p[1][1],p[1][2],p[1][3],p[1][4]};
|
|
end
|
|
end
|
|
-- no front doors found through beds? then take a look if the workplaces found doors
|
|
if( #building_data.front_door_list < 1 ) then
|
|
for i,p in ipairs( paths ) do
|
|
if( p and p[1] ) then
|
|
local d = p[1][ #p[1] ];
|
|
building_data.front_door_list[i] = {d[1],d[2],d[3]};
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return building_data;
|
|
end
|