improved house-village-collusion-detection so that single houses do not conflict with villages
parent
e95523c06a
commit
7fc6f5fc5e
126
villages.lua
126
villages.lua
|
@ -34,11 +34,10 @@ mg_villages.villages_at_point = function(minp, noise1)
|
|||
|
||||
-- fallback: type "nore" (that is what the mod originally came with)
|
||||
local village_type = 'nore';
|
||||
village_type = mg_villages.village_types[ pr:next(1, #mg_villages.village_types )]; -- select a random type
|
||||
-- if this is the first village for this world, take a medieval one
|
||||
if( (not( mg_villages.all_villages ) or mg_villages.anz_villages < 1) and minetest.get_modpath("cottages") and mg_villages.FIRST_VILLAGE_TYPE) then
|
||||
village_type = mg_villages.FIRST_VILLAGE_TYPE;
|
||||
else
|
||||
village_type = mg_villages.village_types[ pr:next(1, #mg_villages.village_types )]; -- select a random type
|
||||
end
|
||||
|
||||
if( not( mg_villages.village_type_data[ village_type ] )) then
|
||||
|
@ -80,7 +79,7 @@ local function choose_building(l, pr, village_type)
|
|||
local p = pr:next(1, 3000)
|
||||
|
||||
for _, b in ipairs( mg_villages.village_type_data[ village_type ][ 'building_list'] ) do
|
||||
if mg_villages.BUILDINGS[ b ].max_weight[ village_type ] >= p then
|
||||
if (mg_villages.BUILDINGS[ b ].max_weight[ village_type ] and mg_villages.BUILDINGS[ b ].max_weight[ village_type ] >= p) then
|
||||
|
||||
-- for b, i in ipairs(mg_villages.BUILDINGS) do
|
||||
-- if i.weight[ village_type ] and i.weight[ village_type ] > 0 and i.max_weight and i.max_weight[ village_type ] and i.max_weight[ village_type ] >= p then
|
||||
|
@ -670,7 +669,7 @@ end
|
|||
-- creates individual buildings outside of villages;
|
||||
-- the data structure is like that of a village, except that bpos (=buildings to be placed) is already set;
|
||||
-- Note: one building per mapchunk is more than enough (else it would look too crowded);
|
||||
mg_villages.houses_in_one_mapchunk = function( minp, mapchunk_size, villages, vnoise )
|
||||
mg_villages.house_in_one_mapchunk = function( minp, mapchunk_size, vnoise )
|
||||
|
||||
local pr = PseudoRandom(mg_villages.get_bseed(minp))
|
||||
-- only each mg_villages.INVERSE_HOUSE_DENSITY th mapchunk gets a building
|
||||
|
@ -689,7 +688,7 @@ mg_villages.houses_in_one_mapchunk = function( minp, mapchunk_size, villages, vn
|
|||
local btype, rotation, bsizex, bsizez, mirror = choose_building_rot({}, pr, orient1, 'single');
|
||||
if( not( bsizex )) then
|
||||
mg_villages.print( mg_villages.DEBUG_LEVEL_INFO, 'FAILURE to generate a building.');
|
||||
btype, rotation, bsizex, bsizez, mirror = choose_building_rot({}, pr, orient1, 'lumberjack');
|
||||
btype, rotation, bsizex, bsizez, mirror = choose_building_rot({}, pr, orient1, 'nore');
|
||||
end
|
||||
-- if no building was found, give up
|
||||
if( not( bsizex ) or not(mg_villages.BUILDINGS[ btype ].weight)) then
|
||||
|
@ -756,31 +755,9 @@ mg_villages.houses_in_one_mapchunk = function( minp, mapchunk_size, villages, vn
|
|||
|
||||
-- these values have to be determined once per village; afterwards, they need to be fixed
|
||||
-- if a village has been generated already, it will continue to exist
|
||||
if( mg_villages.all_villages[ village_id ] ) then
|
||||
return village;
|
||||
end
|
||||
|
||||
-- now check if this village can be placed here or if it intersects with another village in any critical manner;
|
||||
-- the village area may intersect (=unproblematic; may even look nice), but the actual building must not be inside another village
|
||||
for _,v in ipairs(villages) do
|
||||
-- make sure that houses do not spawn inside other villages
|
||||
local min_dist_factor = 10;
|
||||
if( v.is_single_house ) then
|
||||
min_dist_factor = v.vs * 2;
|
||||
else
|
||||
min_dist_factor = v.vs * 3;
|
||||
end
|
||||
-- abort if the new building can't be placed here
|
||||
if( math.abs( blencenx - v.vx ) < min_dist_factor
|
||||
or math.abs( blencenz - v.vz ) < min_dist_factor
|
||||
or mg_villages.inside_village_area(blencenx, blencenz, v, vnoise)
|
||||
or mg_villages.inside_village_area(bx, bz, v, vnoise)
|
||||
or mg_villages.inside_village_area(bx+bsizex, bz, v, vnoise)
|
||||
or mg_villages.inside_village_area(bx, bz+bsizez, v, vnoise)
|
||||
or mg_villages.inside_village_area(bx+bsizex, bz+bsizez, v, vnoise)) then
|
||||
return {};
|
||||
end
|
||||
end
|
||||
-- if( mg_villages.all_villages[ village_id ] ) then
|
||||
-- return village;
|
||||
-- end
|
||||
|
||||
if( mg_villages.all_villages and mg_villages.all_villages[ village_id ] and mg_villages.all_villages[ village_id ].optimal_height) then
|
||||
village.optimal_height = mg_villages.all_villages[ village_id ].optimal_height;
|
||||
|
@ -790,30 +767,103 @@ mg_villages.houses_in_one_mapchunk = function( minp, mapchunk_size, villages, vn
|
|||
|
||||
village.to_add_data = {};
|
||||
village.to_add_data.bpos = { {x=bx, y=village.vh, z=bz, btype=btype, bsizex=bsizex, bsizez=bsizez, brotate = rotation, road_nr = 0, side=1, o=orient1, mirror=mirror }}
|
||||
-- there may be quite a lot of single houses added; plus they are less intresting than entire villages. Thus, logfile spam is reduced
|
||||
mg_villages.print( mg_villages.DEBUG_LEVEL_WARNING, 'adding SINGLE HOUSE of type '..tostring( village.village_type )..
|
||||
' to map at '..tostring( village.vx )..':'..tostring( village.vz )..'.');
|
||||
|
||||
return village;
|
||||
end
|
||||
|
||||
|
||||
mg_villages.house_in_mapchunk_mark_intersection = function( villages, c, vnoise ) -- c: candidate for a new one-house-village
|
||||
-- now check if this village can be placed here or if it intersects with another village in any critical manner;
|
||||
-- the village area may intersect (=unproblematic; may even look nice), but the actual building must not be inside another village
|
||||
|
||||
-- exclude misconfigured villages
|
||||
if( not( c ) or not( c.to_add_data )) then
|
||||
--print('WRONG DATA: '..minetest.serialize( c ));
|
||||
c.areas_intersect = 1;
|
||||
return;
|
||||
end
|
||||
|
||||
local bx = c.to_add_data.bpos[1].x;
|
||||
local bz = c.to_add_data.bpos[1].z;
|
||||
local bsizex = c.to_add_data.bpos[1].bsizex;
|
||||
local bsizez = c.to_add_data.bpos[1].bsizez;
|
||||
|
||||
-- make sure that the house does not intersect with the area of a village
|
||||
for _,v in ipairs( villages ) do
|
||||
local id = v.vx..':'..v.vz;
|
||||
if( id and mg_villages.all_villages and mg_villages.all_villages[ id ] ) then
|
||||
v = mg_villages.all_villages[ id ];
|
||||
end
|
||||
|
||||
if( v.vx ~= c.vx and v.vz ~= c.vz ) then
|
||||
local dist = math.sqrt( ( c.vx - v.vx ) * ( c.vx - v.vx )
|
||||
+ ( c.vz - v.vz ) * ( c.vz - v.vz ));
|
||||
if( dist < ( c.vs + v.vs )*1.1 ) then
|
||||
mg_villages.print( mg_villages.DEBUG_LEVEL_WARNING, 'DROPPING house at '..c.vx..':'..c.vz..' because it is too close to '..v.vx..':'..c.vx);
|
||||
c.areas_intersect = 1;
|
||||
-- the other village can't be spawned either as we don't know which one will be loaded first
|
||||
if( v.is_single_house ) then
|
||||
v.areas_intersect = 1;
|
||||
end
|
||||
end
|
||||
|
||||
if( mg_villages.inside_village_area( c.vx, c.vz, v, vnoise)
|
||||
or mg_villages.inside_village_area( bx, bz, v, vnoise)
|
||||
or mg_villages.inside_village_area((bx+bsizex), bz, v, vnoise)
|
||||
or mg_villages.inside_village_area((bx+bsizex), (bz+bsizez), v, vnoise)
|
||||
or mg_villages.inside_village_area( bx, (bz+bsizez), v, vnoise)) then
|
||||
|
||||
mg_villages.print( mg_villages.DEBUG_LEVEL_WARNING, 'DROPPING house at '..c.vx..':'..c.vz..' due to intersection with village at '..id);
|
||||
c.areas_intersect = 1;
|
||||
-- the other village can't be spawned either as we don't know which one will be loaded first
|
||||
if( v.is_single_house ) then
|
||||
v.areas_intersect = 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- we need to determine where single houses will be placed in neighbouring mapchunks as well because
|
||||
-- they may be so close to the border that they will affect this mapchunk
|
||||
mg_villages.houses_in_mapchunk = function( minp, mapchunk_size, villages )
|
||||
local village_noise = minetest.get_perlin(7635, 3, 0.5, 16);
|
||||
local vcr = 1; --mg_villages.VILLAGE_CHECK_RADIUS
|
||||
|
||||
local village_candidates = {};
|
||||
local vcr = 2; --mg_villages.VILLAGE_CHECK_RADIUS
|
||||
for xi = -vcr, vcr do
|
||||
for zi = -vcr, vcr do
|
||||
local new_village = mg_villages.houses_in_one_mapchunk(
|
||||
local new_village = mg_villages.house_in_one_mapchunk(
|
||||
{x=minp.x+(xi*mapchunk_size), y=minp.y, z=minp.z+(zi*mapchunk_size)},
|
||||
mapchunk_size,
|
||||
villages,
|
||||
village_noise );
|
||||
if( new_village and new_village.vs and new_village.vx and new_village.vz ) then
|
||||
table.insert( villages, new_village );
|
||||
table.insert( village_candidates, new_village );
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _,candidate in ipairs(village_candidates) do
|
||||
-- mark all one-house-village-candidates that intersect with villages in this mapchunk
|
||||
mg_villages.house_in_mapchunk_mark_intersection( villages, candidate, village_noise );
|
||||
-- mark all one-house-village-candidates that intersect with other candidates in this mapchunk
|
||||
mg_villages.house_in_mapchunk_mark_intersection( village_candidates, candidate, village_noise );
|
||||
end
|
||||
|
||||
-- now add those villages that do not intersect with others and which *may* at least be part of this mapchunk
|
||||
local d = math.ceil( mapchunk_size / 2 );
|
||||
for _,candidate in ipairs(village_candidates) do
|
||||
if( not( candidate.areas_intersect )
|
||||
and (candidate.vx > minp.x - d or candidate.vx < (mapchunk_size+d) )
|
||||
and (candidate.vz > minp.z - d or candidate.vz < (mapchunk_size+d) )) then
|
||||
table.insert( villages, candidate );
|
||||
|
||||
-- there may be quite a lot of single houses added; plus they are less intresting than entire villages. Thus, logfile spam is reduced
|
||||
mg_villages.print( mg_villages.DEBUG_LEVEL_WARNING, 'adding SINGLE HOUSE of type '..tostring( candidate.village_type )..
|
||||
' to map at '..tostring( candidate.vx )..':'..tostring( candidate.vz )..'.');
|
||||
end
|
||||
end
|
||||
return villages;
|
||||
end
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue