2013-09-22 08:15:22 +02:00
function village_at_point ( minp , noise1 )
2013-09-21 15:07:43 +02:00
local bseed
for xi = - 2 , 2 do
for zi = - 2 , 0 do
if xi ~= 0 or zi ~= 0 then
local pi = PseudoRandom ( get_bseed ( { x = minp.x + 80 * xi , z = minp.z + 80 * zi } ) )
2013-09-22 15:56:10 +02:00
if pi : next ( 1 , 400 ) <= 28 and noise1 : get2d ( { x = minp.x + 80 * xi , z = minp.z + 80 * zi } ) >- 0.3 then return 0 , 0 , 0 , 0 end
2013-09-21 15:07:43 +02:00
end
end
end
local pr = PseudoRandom ( get_bseed ( minp ) )
2013-09-22 15:52:03 +02:00
if pr : next ( 1 , 400 ) > 28 then return 0 , 0 , 0 , 0 end
2013-09-21 15:07:43 +02:00
local x = pr : next ( minp.x , minp.x + 79 )
local z = pr : next ( minp.z , minp.z + 79 )
2013-09-22 15:56:10 +02:00
if noise1 : get2d ( { x = x , y = z } ) <- 0.3 then return 0 , 0 , 0 , 0 end
2013-09-21 15:07:43 +02:00
local size = pr : next ( 20 , 40 )
local height = pr : next ( 5 , 20 )
print ( " A village spawned at: x= " .. x .. " , z= " .. z )
return x , z , size , height
end
2013-09-22 15:38:07 +02:00
--local function dist_center2(ax, bsizex, az, bsizez)
-- return math.max((ax+bsizex)*(ax+bsizex),ax*ax)+math.max((az+bsizez)*(az+bsizez),az*az)
--end
local function inside_village2 ( bx , sx , bz , sz , vx , vz , vs , vnoise )
return inside_village ( bx , bz , vx , vz , vs , vnoise ) and inside_village ( bx + sx , bz , vx , vz , vs , vnoise ) and inside_village ( bx , bz + sz , vx , vz , vs , vnoise ) and inside_village ( bx + sx , bz + sz , vx , vz , vs , vnoise )
2013-09-22 14:21:25 +02:00
end
local function choose_building ( l , pr )
:: choose ::
p = pr : next ( 1 , 3000 )
for b , i in ipairs ( buildings ) do
if i.max_weight > p then
btype = b
break
end
end
if buildings [ btype ] . pervillage ~= nil then
local n = 0
for j = 1 , # l do
if l [ j ] . btype == btype then
n = n + 1
end
end
if n >= buildings [ btype ] . pervillage then
goto choose
end
end
return btype
end
local function choose_building_rot ( l , pr )
local btype = choose_building ( l , pr )
local rotation
if buildings [ btype ] . no_rotate then
rotation = 0
else
rotation = pr : next ( 0 , 3 )
end
bsizex = buildings [ btype ] . sizex
bsizez = buildings [ btype ] . sizez
if rotation % 2 == 1 then
bsizex , bsizez = bsizez , bsizex
end
return btype , rotation , bsizex , bsizez
end
2013-09-22 15:38:07 +02:00
local function placeable ( bx , bz , bsizex , bsizez , l , exclude_roads )
2013-09-22 14:21:25 +02:00
for _ , a in ipairs ( l ) do
2013-09-22 15:38:07 +02:00
if ( a.btype ~= " road " or not exclude_roads ) and math.abs ( bx + bsizex / 2 - a.x - a.bsizex / 2 ) <= ( bsizex + a.bsizex ) / 2 and math.abs ( bz + bsizez / 2 - a.z - a.bsizez / 2 ) <= ( bsizez + a.bsizez ) / 2 then return false end
2013-09-22 14:21:25 +02:00
end
return true
end
2013-09-22 15:38:07 +02:00
local function road_in_building ( rx , rz , rdx , rdz , roadsize , l )
if rdx == 0 then
return not placeable ( rx - roadsize + 1 , rz , 2 * roadsize - 2 , 0 , l , true )
else
return not placeable ( rx , rz - roadsize + 1 , 0 , 2 * roadsize - 2 , l , true )
end
end
local function when ( a , b , c )
if a then return b else return c end
end
local function generate_road ( vx , vz , vs , vh , l , pr , roadsize , rx , rz , rdx , rdz , vnoise )
2013-09-22 14:21:25 +02:00
local calls_to_do = { }
local rxx = rx
local rzz = rz
local mx , m2x , mz , m2z
mx , m2x , mz , m2z = rx , rx , rz , rz
2013-09-22 15:38:07 +02:00
while inside_village ( rx , rz , vx , vz , vs , vnoise ) and not road_in_building ( rx , rz , rdx , rdz , roadsize , l ) do
if roadsize > 1 and pr : next ( 1 , 4 ) == 1 then
2013-09-22 14:21:25 +02:00
--generate_road(vx, vz, vs, vh, l, pr, roadsize-1, rx, rz, math.abs(rdz), math.abs(rdx))
calls_to_do [ # calls_to_do + 1 ] = { rx = rx + ( roadsize - 1 ) * rdx , rz = rz + ( roadsize - 1 ) * rdz , rdx = math.abs ( rdz ) , rdz = math.abs ( rdx ) }
2013-09-22 15:38:07 +02:00
m2x = rx + ( roadsize - 1 ) * rdx
m2z = rz + ( roadsize - 1 ) * rdz
2013-09-22 14:21:25 +02:00
rx = rx + ( 2 * roadsize - 1 ) * rdx
rz = rz + ( 2 * roadsize - 1 ) * rdz
2013-09-22 15:38:07 +02:00
end
--else
2013-09-22 14:21:25 +02:00
:: loop ::
2013-09-22 15:38:07 +02:00
if not inside_village ( rx , rz , vx , vz , vs , vnoise ) or road_in_building ( rx , rz , rdx , rdz , roadsize , l ) then goto exit1 end
2013-09-22 14:21:25 +02:00
btype , rotation , bsizex , bsizez = choose_building_rot ( l , pr )
2013-09-22 15:38:07 +02:00
local bx = rx + math.abs ( rdz ) * ( roadsize + 1 ) - when ( rdx ==- 1 , bsizex - 1 , 0 )
local bz = rz + math.abs ( rdx ) * ( roadsize + 1 ) - when ( rdz ==- 1 , bsizez - 1 , 0 )
if not placeable ( bx , bz , bsizex , bsizez , l ) or not inside_village2 ( bx , bsizex , bz , bsizez , vx , vz , vs , vnoise ) then --dist_center2(bx-vx, bsizex, bz-vz, bsizez)>vs*vs then
2013-09-22 14:21:25 +02:00
rx = rx + rdx
rz = rz + rdz
goto loop
end
rx = rx + ( bsizex + 1 ) * rdx
rz = rz + ( bsizez + 1 ) * rdz
mx = rx - 2 * rdx
mz = rz - 2 * rdz
l [ # l + 1 ] = { x = bx , y = vh , z = bz , btype = btype , bsizex = bsizex , bsizez = bsizez , brotate = rotation }
2013-09-22 15:38:07 +02:00
--end
2013-09-22 14:21:25 +02:00
end
:: exit1 ::
2013-09-22 15:38:07 +02:00
if road_in_building ( rx , rz , rdx , rdz , roadsize , l ) then
mx = rx - 2 * rdx
mz = rz - 2 * rdz
end
2013-09-22 14:21:25 +02:00
rx = rxx
rz = rzz
2013-09-22 15:38:07 +02:00
while inside_village ( rx , rz , vx , vz , vs , vnoise ) and not road_in_building ( rx , rz , rdx , rdz , roadsize , l ) do
if roadsize > 1 and pr : next ( 1 , 4 ) == 1 then
2013-09-22 14:21:25 +02:00
--generate_road(vx, vz, vs, vh, l, pr, roadsize-1, rx, rz, -math.abs(rdz), -math.abs(rdx))
calls_to_do [ # calls_to_do + 1 ] = { rx = rx + ( roadsize - 1 ) * rdx , rz = rz + ( roadsize - 1 ) * rdz , rdx =- math.abs ( rdz ) , rdz =- math.abs ( rdx ) }
2013-09-22 15:38:07 +02:00
m2x = rx + ( roadsize - 1 ) * rdx
m2z = rz + ( roadsize - 1 ) * rdz
2013-09-22 14:21:25 +02:00
rx = rx + ( 2 * roadsize - 1 ) * rdx
rz = rz + ( 2 * roadsize - 1 ) * rdz
2013-09-22 15:38:07 +02:00
end
--else
2013-09-22 14:21:25 +02:00
:: loop ::
2013-09-22 15:38:07 +02:00
if not inside_village ( rx , rz , vx , vz , vs , vnoise ) or road_in_building ( rx , rz , rdx , rdz , roadsize , l ) then goto exit2 end
2013-09-22 14:21:25 +02:00
btype , rotation , bsizex , bsizez = choose_building_rot ( l , pr )
2013-09-22 15:38:07 +02:00
local bx = rx - math.abs ( rdz ) * ( bsizex + roadsize ) - when ( rdx ==- 1 , bsizex - 1 , 0 )
local bz = rz - math.abs ( rdx ) * ( bsizez + roadsize ) - when ( rdz ==- 1 , bsizez - 1 , 0 )
if not placeable ( bx , bz , bsizex , bsizez , l ) or not inside_village2 ( bx , bsizex , bz , bsizez , vx , vz , vs , vnoise ) then --dist_center2(bx-vx, bsizex, bz-vz, bsizez)>vs*vs then
2013-09-22 14:21:25 +02:00
rx = rx + rdx
rz = rz + rdz
goto loop
end
rx = rx + ( bsizex + 1 ) * rdx
rz = rz + ( bsizez + 1 ) * rdz
m2x = rx - 2 * rdx
m2z = rz - 2 * rdz
l [ # l + 1 ] = { x = bx , y = vh , z = bz , btype = btype , bsizex = bsizex , bsizez = bsizez , brotate = rotation }
2013-09-22 15:38:07 +02:00
--end
2013-09-22 14:21:25 +02:00
end
:: exit2 ::
2013-09-22 15:38:07 +02:00
if road_in_building ( rx , rz , rdx , rdz , roadsize , l ) then
m2x = rx - 2 * rdx
m2z = rz - 2 * rdz
2013-09-22 14:21:25 +02:00
end
2013-09-22 15:38:07 +02:00
mx = rdx * math.max ( rdx * mx , rdx * m2x )
mz = rdz * math.max ( rdz * mz , rdz * m2z )
2013-09-22 14:21:25 +02:00
if rdx == 0 then
rxmin = rx - roadsize + 1
rxmax = rx + roadsize - 1
rzmin = math.min ( rzz , mz )
rzmax = math.max ( rzz , mz )
else
rzmin = rz - roadsize + 1
rzmax = rz + roadsize - 1
rxmin = math.min ( rxx , mx )
rxmax = math.max ( rxx , mx )
end
l [ # l + 1 ] = { x = rxmin , y = vh , z = rzmin , btype = " road " , bsizex = rxmax - rxmin + 1 , bsizez = rzmax - rzmin + 1 , brotate = 0 }
for _ , i in ipairs ( calls_to_do ) do
2013-09-22 15:38:07 +02:00
generate_road ( vx , vz , vs , vh , l , pr , roadsize - 1 , i.rx , i.rz , i.rdx , i.rdz , vnoise )
2013-09-22 14:21:25 +02:00
end
2013-09-21 15:07:43 +02:00
end
2013-09-22 15:38:07 +02:00
local function generate_bpos ( vx , vz , vs , vh , pr , vnoise )
2013-09-22 14:21:25 +02:00
--[=[local l={}
2013-09-22 10:13:20 +02:00
local total_weight = 0
for _ , i in ipairs ( buildings ) do
2013-09-22 10:14:57 +02:00
if i.weight == nil then i.weight = 1 end
2013-09-22 10:13:20 +02:00
total_weight = total_weight + i.weight
i.max_weight = total_weight
end
local multiplier = 3000 / total_weight
for _ , i in ipairs ( buildings ) do
i.max_weight = i.max_weight * multiplier
end
2013-09-22 14:21:25 +02:00
for i = 1 , 2000 do
2013-09-21 15:07:43 +02:00
bx = pr : next ( vx - vs , vx + vs )
bz = pr : next ( vz - vs , vz + vs )
2013-09-21 19:16:04 +02:00
:: choose ::
2013-09-22 10:13:20 +02:00
--[[btype = pr:next(1, #buildings)
2013-09-21 19:16:04 +02:00
if buildings [ btype ] . chance ~= nil then
if pr : next ( 1 , buildings [ btype ] . chance ) ~= 1 then
goto choose
end
2013-09-22 10:13:20 +02:00
end ] ]
p = pr : next ( 1 , 3000 )
for b , i in ipairs ( buildings ) do
if i.max_weight > p then
btype = b
break
end
2013-09-21 19:16:04 +02:00
end
2013-09-21 23:09:41 +02:00
if buildings [ btype ] . pervillage ~= nil then
local n = 0
for j = 1 , # l do
if l [ j ] . btype == btype then
n = n + 1
end
end
if n >= buildings [ btype ] . pervillage then
goto choose
end
end
2013-09-22 14:21:25 +02:00
local rotation
if buildings [ btype ] . no_rotate then
rotation = 0
else
rotation = pr : next ( 0 , 3 )
end
2013-09-21 15:07:43 +02:00
bsizex = buildings [ btype ] . sizex
bsizez = buildings [ btype ] . sizez
2013-09-22 14:21:25 +02:00
if rotation % 2 == 1 then
bsizex , bsizez = bsizez , bsizex
end
2013-09-21 15:07:43 +02:00
if dist_center2 ( bx - vx , bsizex , bz - vz , bsizez ) > vs * vs then goto out end
for _ , a in ipairs ( l ) do
2013-09-22 08:14:00 +02:00
if math.abs ( bx - a.x ) <= ( bsizex + a.bsizex ) / 2 + 2 and math.abs ( bz - a.z ) <= ( bsizez + a.bsizez ) / 2 + 2 then goto out end
2013-09-21 15:07:43 +02:00
end
2013-09-22 14:21:25 +02:00
l [ # l + 1 ] = { x = bx , y = vh , z = bz , btype = btype , bsizex = bsizex , bsizez = bsizez , brotate = rotation }
2013-09-21 15:07:43 +02:00
:: out ::
end
2013-09-22 14:21:25 +02:00
return l ] = ] --
local l = { }
2013-09-22 15:38:07 +02:00
local rx = vx - vs
2013-09-22 14:21:25 +02:00
local rz = vz
2013-09-22 15:38:07 +02:00
while inside_village ( rx , rz , vx , vz , vs , vnoise ) do
rx = rx - 1
end
rx = rx + 5
generate_road ( vx , vz , vs , vh , l , pr , 3 , rx , rz , 1 , 0 , vnoise )
2013-09-21 15:07:43 +02:00
return l
2013-09-22 14:21:25 +02:00
--[=[while rx1 < vx+vs do
local building = choose_building ( l , pr )
local rotation
if buildings [ btype ] . no_rotate then
rotation = 0
else
rotation = pr : next ( 0 , 3 )
end
bsizex = buildings [ btype ] . sizex
bsizez = buildings [ btype ] . sizez
if rotation % 2 == 1 then
bsizex , bsizez = bsizez , bsizex
end
local bx = rx1
rx1 = rx1 + bsizex + 1
local bz = rz - bsizez - 3
if dist_center2 ( bx - vx , bsizex , bz - vz , bsizez ) > vs * vs then goto out end
l [ # l + 1 ] = { x = bx , y = vh , z = bz , btype = btype , bsizex = bsizex , bsizez = bsizez , brotate = rotation }
:: out ::
end
while rx2 < vx + vs do
local building = choose_building ( l , pr )
local rotation
if buildings [ btype ] . no_rotate then
rotation = 0
else
rotation = pr : next ( 0 , 3 )
end
bsizex = buildings [ btype ] . sizex
bsizez = buildings [ btype ] . sizez
if rotation % 2 == 1 then
bsizex , bsizez = bsizez , bsizex
end
local bx = rx2
rx2 = rx2 + bsizex + 1
local bz = rz + 3
if dist_center2 ( bx - vx , bsizex , bz - vz , bsizez ) > vs * vs then goto out end
l [ # l + 1 ] = { x = bx , y = vh , z = bz , btype = btype , bsizex = bsizex , bsizez = bsizez , brotate = rotation }
:: out ::
end
return l ] = ]
2013-09-21 15:07:43 +02:00
end
2013-09-21 15:42:00 +02:00
local function generate_building ( pos , minp , maxp , data , a , pr , extranodes )
2013-09-21 15:07:43 +02:00
local binfo = buildings [ pos.btype ]
2013-09-22 18:03:27 +02:00
local scm
if type ( binfo.scm ) == " string " then
local f , err = io.open ( minetest.get_modpath ( " mg " ) .. " /schems/ " .. binfo.scm .. " .we " , " r " )
if not f then
error ( " Could not open schematic ' " .. binfo.scm .. " .we': " .. err )
end
value = f : read ( " *a " )
f : close ( )
value = value : gsub ( " return%s*{ " , " " , 1 ) : gsub ( " }%s*$ " , " " , 1 )
local escaped = value : gsub ( " \\ \\ " , " @@ " ) : gsub ( " \\ \" " , " @@ " ) : gsub ( " ( \" [^ \" ]* \" ) " , function ( s ) return string.rep ( " @ " , # s ) end )
local startpos , startpos1 , endpos = 1 , 1
local nodes = { }
while true do
startpos , endpos = escaped : find ( " },%s*{ " , startpos )
if not startpos then
break
end
local current = value : sub ( startpos1 , startpos )
table.insert ( nodes , minetest.deserialize ( " return " .. current ) )
startpos , startpos1 = endpos , endpos
end
table.insert ( nodes , minetest.deserialize ( " return " .. value : sub ( startpos1 ) ) )
scm = { }
local maxx , maxy , maxz = - 1 , - 1 , - 1
for i = 1 , # nodes do
local ent = nodes [ i ]
if ent.x > maxx then
maxx = ent.x
end
if ent.y > maxy then
maxy = ent.y
end
if ent.z > maxz then
maxz = ent.z
end
if scm [ ent.y ] == nil then
scm [ ent.y ] = { }
end
if scm [ ent.y ] [ ent.x ] == nil then
scm [ ent.y ] [ ent.x ] = { }
end
if ent.param2 == nil then
ent.param2 = 0
end
if ent.meta == nil then
ent.meta = { fields = { } , inventory = { } }
end
if ent.param2 == 0 and # ent.meta . fields == 0 and # ent.meta . inventory == 0 then
scm [ ent.y ] [ ent.x ] [ ent.z ] = minetest.get_content_id ( ent.name )
else
scm [ ent.y ] [ ent.x ] [ ent.z ] = { node = { name = ent.name , param2 = ent.param2 } , meta = ent.meta }
end
end
local c_ignore = minetest.get_content_id ( " ignore " )
for x = 1 , maxx do
for y = 1 , maxy do
for z = 1 , maxz do
if scm [ ent.y ] == nil then
scm [ ent.y ] = { }
end
if scm [ ent.y ] [ ent.x ] == nil then
scm [ ent.y ] [ ent.x ] = { }
end
if scm [ ent.y ] [ ent.x ] [ ent.z ] == nil then
scm [ ent.y ] [ ent.x ] [ ent.z ] = c_ignore
end
end
end
end
else
scm = binfo.scm
end
scm = rotate ( scm , pos.brotate )
2013-09-21 20:46:18 +02:00
local t
2013-09-22 14:21:25 +02:00
for x = 0 , pos.bsizex - 1 do
for y = 0 , binfo.ysize - 1 do
for z = 0 , pos.bsizez - 1 do
2013-09-22 00:02:28 +02:00
ax , ay , az = pos.x + x , pos.y + y + binfo.yoff , pos.z + z
2013-09-22 07:13:41 +02:00
if ( ax >= minp.x and ax <= maxp.x ) and ( ay >= minp.y and ay <= maxp.y ) and ( az >= minp.z and az <= maxp.z ) then
2013-09-22 14:21:25 +02:00
t = scm [ y + 1 ] [ x + 1 ] [ z + 1 ]
2013-09-22 00:02:28 +02:00
if type ( t ) == " table " then
table.insert ( extranodes , { node = t.node , meta = t.meta , pos = { x = ax , y = ay , z = az } , } )
2013-09-22 10:13:20 +02:00
elseif t ~= c_ignore then
2013-09-22 00:02:28 +02:00
data [ a : index ( ax , ay , az ) ] = t
end
2013-09-21 19:16:04 +02:00
end
2013-09-21 15:07:43 +02:00
end
end
end
end
2013-09-22 15:38:07 +02:00
local MIN_DIST = 5
local function pos_far_buildings ( x , z , l )
for _ , a in ipairs ( l ) do
if a.x - MIN_DIST <= x and x <= a.x + a.bsizex + MIN_DIST and a.z - MIN_DIST <= z and z <= a.z + a.bsizez + MIN_DIST then
return false
end
end
return true
end
function generate_village ( vx , vz , vs , vh , minp , maxp , data , a , vnoise , to_grow )
2013-09-21 15:07:43 +02:00
local seed = get_bseed ( { x = vx , z = vz } )
local pr = PseudoRandom ( seed )
2013-09-22 15:38:07 +02:00
local bpos = generate_bpos ( vx , vz , vs , vh , pr , vnoise )
2013-09-21 15:42:00 +02:00
local extranodes = { }
2013-09-21 15:07:43 +02:00
for _ , pos in ipairs ( bpos ) do
2013-09-21 15:42:00 +02:00
generate_building ( pos , minp , maxp , data , a , pr , extranodes )
2013-09-21 15:07:43 +02:00
end
2013-09-22 15:38:07 +02:00
local pr = PseudoRandom ( seed )
for _ , g in ipairs ( to_grow ) do
if pos_far_buildings ( g.x , g.z , bpos ) then
if g.content == c_sapling then
add_tree ( data , a , g.x , g.y , g.z , minp , maxp , c_tree , c_leaves , pr )
elseif g.content == c_junglesapling then
add_jungletree ( data , a , g.x , g.y , g.z , minp , maxp , c_jungletree , c_jungleleaves , pr )
elseif g.content == c_savannasapling then
add_savannatree ( data , a , g.x , g.y , g.z , minp , maxp , c_savannatree , c_savannaleaves , pr )
elseif g.content == " savannabush " then
add_savannabush ( data , a , g.x , g.y , g.z , minp , maxp , c_savannatree , c_savannaleaves , pr )
elseif g.content == c_pinesapling then
add_pinetree ( data , a , g.x , g.y , g.z , minp , maxp , c_pinetree , c_pineleaves , c_snow , pr )
elseif g.content == c_cactus then
ch = pr : next ( 0 , 3 )
for yy = math.max ( g.y , minp.y ) , math.min ( g.y + ch , maxp.y ) do
data [ a : index ( x , yy , z ) ] = c_cactus
end
elseif g.content == c_papyrus then
ch = pr : next ( 1 , 3 )
for yy = math.max ( g.y , minp.y ) , math.min ( g.y + ch , maxp.y ) do
data [ a : index ( x , yy , z ) ] = c_papyrus
end
end
end
end
2013-09-21 15:42:00 +02:00
return extranodes
2013-09-21 15:07:43 +02:00
end