-- Set singlenode mapgen
core.set_mapgen_setting('mg_name', 'singlenode', true)

-- Set a fixed seed so the islands backdrop used by levels
-- will stay consistent for all players
core.set_mapgen_setting('seed', '908245308192087', true)

-- Force mapgen limit so the game has enough place for all
-- the levels.
core.set_mapgen_setting("mapgen_limit", 3000, true)

local vm_data = {}
local vm_data_p2 = {}

local c_stone = core.get_content_id("cow_core:stone")
local c_dirt = core.get_content_id("cow_core:dirt")
local c_dirt_with_grass = core.get_content_id("cow_core:grass_dirt_block")
local c_grass = core.get_content_id("cow_core:grass_block")
local c_asphalt = core.get_content_id("cow_core:asphalt")
local c_asphalt_stripe = core.get_content_id("cow_core:asphalt_stripe_dashed")
local c_asphalt_side = core.get_content_id("cow_core:asphalt_stripe_side")
local c_sign_post = core.get_content_id("cow_core:sign_steel_post")
local c_sign_90 = core.get_content_id("cow_core:sign_road_90")

local GROUND_LEVEL = 0
local ROAD_Z = -60
local ROAD_SIGN_DIST = 500

local map_noise

core.register_decoration({
	deco_type = "schematic",
	place_on = "cow_core:grass_block",
	sidelen = 16,
	fill_ratio = 0.00005,
	schematic = core.get_modpath("cow_mapgen").."/schems/cow_mapgen_willow.mts",
	flags = "place_center_x,place_center_z",
})
core.register_decoration({
	deco_type = "simple",
	place_on = "cow_core:grass_block",
	sidelen = 16,
	fill_ratio = 0.05,
	decoration = "cow_core:grass_clump_1",
	param2 = 8,
	param2_max = 10,
})
core.register_decoration({
	deco_type = "simple",
	place_on = "cow_core:grass_block",
	sidelen = 16,
	fill_ratio = 0.04,
	decoration = "cow_core:grass_clump_2",
	param2 = 8,
	param2_max = 10,
})

core.register_decoration({
	deco_type = "simple",
	place_on = "cow_core:grass_block",
	sidelen = 16,
	fill_ratio = 0.005,
	decoration = "cow_core:flower_daisy",
	param2 = 8,
})

-- Normal-sized bush
core.register_decoration({
	deco_type = "simple",
	place_on = "cow_core:grass_block",
	sidelen = 16,
	fill_ratio = 0.01,
	decoration = "cow_core:bush",
	param2 = 8,
	param2_max = 9,
})
-- Large bush
core.register_decoration({
	deco_type = "simple",
	place_on = "cow_core:grass_block",
	sidelen = 16,
	fill_ratio = 0.001,
	decoration = "cow_core:bush",
	param2 = 24,
	param2_max = 25,
})

core.register_on_generated(function(minp, maxp, seed)
	if not map_noise then
		local size = vector.subtract(maxp, minp)
		-- TODO: Use ValueNoiseMap instead for better performance
		map_noise = ValueNoise({
			seed = 0,
			spread = { x = 200, y = 200, z = 200 },
			lacunarity = 2.0,
			persistence = 0.5,
			scale = 14,
			octaves = 4,
		}, { x = size.x+1, y = size.z+1, z = 1 })
	end

	local vm = core.get_mapgen_object("voxelmanip")
	local emin, emax = vm:get_emerged_area()
	local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})

	vm:get_data(vm_data)
	vm:get_param2_data(vm_data_p2)
	for z = minp.z, maxp.z do
		for x = minp.x, maxp.x do
			local mx = (maxp.x - x) + 1
			local mz = (maxp.z - z) + 1
			local mapval = map_noise:get_2d({x=x, y=z})
			if not mapval then
				mapval = 0
			elseif z < 140 then
				mapval = mapval - (140-z)/14
			end
			if mapval < 0 then
				mapval = 0
			end
			for y = minp.y, maxp.y do
				local mpos = vector.new(x, y, z)
				local vi = area:index(x, y, z)
				if mapval >= y then
					vm_data[vi] = c_stone
				elseif mapval+1 >= y then
					vm_data[vi] = c_dirt
				elseif mapval+2 >= y then
					if z >= ROAD_Z - 3 and z <= ROAD_Z + 3 then
						vm_data[vi] = c_dirt
					else
						vm_data[vi] = c_dirt_with_grass
					end
				elseif mapval+3 >= y then
					if z >= ROAD_Z - 3 and z <= ROAD_Z + 3 then
						if z == ROAD_Z - 3 or z == ROAD_Z + 3 then
							vm_data[vi] = c_dirt
						elseif z == ROAD_Z - 2 then
							vm_data[vi] = c_asphalt_side
							vm_data_p2[vi] = 1
						elseif z == ROAD_Z + 2 then
							vm_data[vi] = c_asphalt_side
							vm_data_p2[vi] = 3
						elseif z == ROAD_Z and x % 3 == 0 then
							vm_data[vi] = c_asphalt_stripe
							vm_data_p2[vi] = 3
						else
							vm_data[vi] = c_asphalt
						end
					else
						vm_data[vi] = c_grass
					end
				elseif mapval+4 >= y or mapval + 5 >= y then
					if x % ROAD_SIGN_DIST == 0 then
						if z == ROAD_Z + 3 or z == ROAD_Z - 3 then
							vm_data[vi] = c_sign_post
						end
					end
				elseif mapval+6 >= y then
					if x % ROAD_SIGN_DIST == 0 then
						if z == ROAD_Z + 3 then
							vm_data[vi] = c_sign_90
							vm_data_p2[vi] = 3
						elseif z == ROAD_Z - 3 then
							vm_data[vi] = c_sign_90
							vm_data_p2[vi] = 1
						end
					end
				end
			end
		end
	end
	vm:set_data(vm_data)
	vm:set_param2_data(vm_data_p2)
	core.generate_decorations(vm)
	vm:calc_lighting()
	vm:write_to_map(true)
end)
