added far better terrain blend (programmed by paramat); added update_liquids

master
Sokomine 2014-11-08 23:01:13 +01:00
parent 2be8658704
commit 32d1e0c1e6
4 changed files with 137 additions and 23 deletions

View File

@ -45,6 +45,8 @@ dofile(mg_villages.modpath.."/map_of_world.lua")
dofile(mg_villages.modpath.."/fill_chest.lua")
-- terrain blending for individual houses
dofile(mg_villages.modpath.."/terrain_blend.lua")
-- the interface for the mapgen;
-- also takes care of spawning the player
dofile(mg_villages.modpath.."/mapgen.lua")

View File

@ -373,8 +373,11 @@ mg_villages.village_area_mark_inside_village_area = function( village_area, vill
local n_rawnoise = village_noise:get2d({x = x, y = z}) -- create new blended terrain
for village_nr, village in ipairs(villages) do
local vn = mg_villages.get_vn(x, z, n_rawnoise, village);
if( village.is_single_house ) then
-- do nothing here; the village area will be specificly marked later on
-- the village core; this is where the houses stand (but there's no house or road at this particular spot)
if( vn <= 40 ) then
elseif( vn <= 40 ) then
village_area[ x ][ z ] = { village_nr, 6};
-- the flattened land around the village where wheat, cotton, trees or grass may be grown (depending on village type)
@ -396,6 +399,14 @@ mg_villages.village_area_mark_inside_village_area = function( village_area, vill
end
end
end
-- single houses get their own form of terrain blend
local pr = PseudoRandom(mg_villages.get_bseed(minp));
for village_nr, village in ipairs( villages ) do
if( village and village.is_single_house and village.to_add_data and village.to_add_data.bpos and #village.to_add_data.bpos>=1) then
mg_villages.village_area_mark_single_house_area( village_area, minp, maxp, village.to_add_data.bpos[1], pr, village_nr );
end
end
end
@ -710,26 +721,28 @@ mg_villages.place_villages_via_voxelmanip = function( villages, minp, maxp, vm,
mg_villages.generate_village( village, village_noise);
t1 = time_elapsed( t1, 'generate_village' );
-- only add artificial snow if the village has at least a size of 15 (else it might look too artificial)
if( not( village.artificial_snow ) and village.vs > 15) then
if( mg_villages.artificial_snow_probability and math.random( 1, mg_villages.artificial_snow_probability )==1) then
village.artificial_snow = 1;
else
village.artificial_snow = 0;
if( not( village.is_single_house )) then
-- only add artificial snow if the village has at least a size of 15 (else it might look too artificial)
if( not( village.artificial_snow ) and village.vs > 15) then
if( mg_villages.artificial_snow_probability and math.random( 1, mg_villages.artificial_snow_probability )==1) then
village.artificial_snow = 1;
else
village.artificial_snow = 0;
end
end
-- will set village_area to N where .. is:
-- 2: a building
-- 3: border around a building
-- 4: a road
-- 5: border around a road
mg_villages.village_area_mark_buildings( village_area, village_nr, village.to_add_data.bpos );
t1 = time_elapsed( t1, 'mark_buildings' );
-- will set village_area to N where .. is:
-- 8: a dirt road
mg_villages.village_area_mark_dirt_roads( village_area, village_nr, village.to_add_data.dirt_roads );
t1 = time_elapsed( t1, 'mark_dirt_roads' );
end
-- will set village_area to N where .. is:
-- 2: a building
-- 3: border around a building
-- 4: a road
-- 5: border around a road
mg_villages.village_area_mark_buildings( village_area, village_nr, village.to_add_data.bpos );
t1 = time_elapsed( t1, 'mark_buildings' );
-- will set village_area to N where .. is:
-- 8: a dirt road
mg_villages.village_area_mark_dirt_roads( village_area, village_nr, village.to_add_data.dirt_roads );
t1 = time_elapsed( t1, 'mark_dirt_roads' );
end
-- if no voxelmanip data was passed on, read the data here
@ -833,6 +846,9 @@ mg_villages.place_villages_via_voxelmanip = function( villages, minp, maxp, vm,
vm:write_to_map(data)
t1 = time_elapsed( t1, 'vm data written' );
vm:update_liquids()
t1 = time_elapsed( t1, 'vm update liquids' );
-- do on_construct calls AFTER the map data has been written - else i.e. realtest fences can not update themshevles
for _, village in ipairs(villages) do
for k, v in pairs( village.to_add_data.extra_calls.on_constr ) do

94
terrain_blend.lua Normal file
View File

@ -0,0 +1,94 @@
-- this function needs to be fed house x, z dimensions and rotation
-- it will then calculate the minimum point (xbmin, avsurfy, zbmin) where the house should be spawned
-- and mark a mapchunk-sized 'house area' for terrain blending
mg_villages.village_area_mark_single_house_area = function(village_area, minp, maxp, pos, pr, village_nr)
local YFLATMIN = 2 -- Lowest flat area height
local FFAPROP = 0.5 -- front flat area proportion of dimension
local np_blend = {
offset = 0,
scale = 1,
spread = {x=12, y=12, z=12},
seed = 38393,
octaves = 3,
persist = 0.67
}
local sidelen = maxp.x - minp.x + 1
local xdim, zdim -- dimensions of house plus front flat area
if pos.brotate == 0 or pos.brotate == 2 then
xdim = pos.bsizex
zdim = pos.bsizez + math.floor(FFAPROP * pos.bsizez)
else
xdim = pos.bsizex + math.floor(FFAPROP * pos.bsizex)
zdim = pos.bsizez
end
local blenrad = math.floor((math.max(xdim, zdim) + 16) / 2) -- radius of blend area
local blendim = 2 * blenrad + 1 -- blend area dimensions
local blencenx = minp.x + pr:next(blenrad+16, sidelen - blenrad - 1 -16) -- blend area centre point
local blencenz = minp.z + pr:next(blenrad+16, sidelen - blenrad - 1 -16)
local minx = blencenx - math.ceil(xdim / 2) -- minimum point of house plus front flat area
local minz = blencenz - math.ceil(zdim / 2)
local xbmin, zbmin -- house minimum point
if pos.brotate == 2 or pos.brotate == 3 then -- N, E
xbmin = minx
zbmin = minz
elseif pos.brotate == 1 then -- W
xbmin = minx + math.floor(FFAPROP * pos.bsizex)
zbmin = minz
else -- pos.brotate = 2, S
xbmin = minx
zbmin = minz + math.floor(FFAPROP * pos.bsizez)
end
-- CHANGE the position of the house so that it sits where the terrain is blended:
-- *** spawn building at (xbmin, avsurfy, zbmin) after landscaping ***
pos.x = xbmin;
pos.z = zbmin;
-- 2D noise perlinmap
local chulens = {x=sidelen, y=sidelen, z=sidelen}
local minpos = {x=minp.x, y=minp.z}
local nvals_blend = minetest.get_perlin_map(np_blend, chulens):get2dMap_flat(minpos)
-- mark mapchunk-sized house area
local ni = 1
-- for z = minp.z, maxp.z do
-- for x = minp.x, maxp.x do -- for each column do
for z = math.max( blencenz - blenrad, minp.z), math.min(blencenz + blenrad, maxp.z), 1 do
for x = math.max( blencenx - blenrad, minp.x), math.min(blencenx + blenrad, maxp.x), 1 do -- for each column do
local xrm = x - minp.x -- relative to mapchunk minp
local zrm = z - minp.z
local xr = x - blencenx -- relative to blend centre
local zr = z - blencenz
local xre1 = (zdim / 2) * (xr / zr)
local zre1 = zdim / 2
local xre2 = xdim / 2
local zre2 = (xdim / 2) * (zr / xr)
local rade1 = math.sqrt(xre1 ^ 2 + zre1 ^ 2)
local rade2 = math.sqrt(xre2 ^ 2 + zre2 ^ 2)
local flatrad = math.min(rade1, rade2) -- radius at edge of rectangular house flat area
local n_absblend = math.abs(nvals_blend[ni])
local blenradn = blenrad - n_absblend * 2 -- vary blend radius
local flatradn = flatrad + n_absblend * 2 -- vary shape of house flat area
local nodrad = math.sqrt(xr ^ 2 + zr ^ 2) -- node radius
if x >= xbmin and x <= xbmin + pos.bsizex -- area reserved for house
and z >= zbmin and z <= zbmin + pos.bsizez then
village_area[ x ][ z ] = {village_nr, 4}
elseif nodrad <= flatradn or (xr == 0 and zr == 0) then -- irregular flat area around house
village_area[ x ][ z ] = {village_nr, 1}
elseif nodrad <= blenradn then -- terrain blend area
local blenprop = ((nodrad - flatradn) / (blenradn - flatradn))
village_area[ x ][ z ] = {village_nr, -1 * blenprop} -- terrain blending
else -- no change to terrain
--village_area[xrm][zrm] = {village_nr, 0}
end
ni = ni + 1
end
end
end

View File

@ -775,8 +775,10 @@ end
-- 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);
for x=-1,1 do
for z=-1,1 do
-- for x=-1,1 do
-- for z=-1,1 do
local x = 0;
local z = 0;
local new_village = mg_villages.houses_in_one_mapchunk(
{x=minp.x+(x*mapchunk_size), y=minp.y, z=minp.z+(z*mapchunk_size)},
mapchunk_size,
@ -785,7 +787,7 @@ mg_villages.houses_in_mapchunk = function( minp, mapchunk_size, villages )
if( new_village and new_village.vs and new_village.vx and new_village.vz ) then
table.insert( villages, new_village );
end
end
end
-- end
-- end
return villages;
end