-
Notifications
You must be signed in to change notification settings - Fork 14
/
analyze_building_for_mobs.lua
254 lines (229 loc) · 9.88 KB
/
analyze_building_for_mobs.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
-- 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] and p[1][ #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