/**
	Gem Grabbers
	Dynamic map with sky islands and hard to reach gems. There is a main island, with at the bottom gem stalactites
	and some smaller islands which also have gem stalactites hanging from the bottom. Each of the smaller islands
	have different materials.
	
	@author Maikel
*/

#include Library_Map


// Called be the engine: draw the complete map here.
protected func InitializeMap(proplist map)
{
	// Retrieve the settings according to the MapSize setting.
	var map_size, main_size, nr_islands;
	if (SCENPAR_MapSize == 1)
	{
		map_size = [240, 200]; main_size = 80; nr_islands = RandomX(6, 7);
	}
	if (SCENPAR_MapSize == 2)
	{
		map_size = [280, 220]; main_size = 90; nr_islands = RandomX(7, 8);
	}
	if (SCENPAR_MapSize == 3)
	{
		map_size = [320, 240]; main_size = 100; nr_islands = RandomX(8, 9);
	}
	
	// Set the map size.
	map->Resize(map_size[0], map_size[1]);
	
	// Draw the main island.
	map->DrawMainIsland(map, main_size);
	
	// Draw a number of sky islands at random positions, each with different resources.
	var resources = [["Coal", "Ore"], ["Coal", "Gold"], ["Firestone", "Coal"], ["Rock", "Ore"], ["Rock", "Coal", "Firestone"], ["Gold", "Ore", "Coal"]];
	while (nr_islands > 0)
	{
		var x = 12 + Random(map.Wdt - 24);
		var y = 26 + Random(map.Hgt - 52);
		var wdt = RandomX(35, 45);
		var hgt = wdt - RandomX(16, 22);
		// DrawIsland itself makes sure there is no other island nearby.
		if (DrawIsland(map, x, y, wdt, hgt, resources[Random(6)]))
			nr_islands--;
	}
	
	// Fix the liquid borders with a library function.
	FixLiquidBorders("Earth");
	
	// Return true to tell the engine a map has been successfully created.
	return true;
}

// Draws the main island with all basic resources
public func DrawMainIsland(proplist map, int size)
{
	// Shape of the main island.
	var island = {Algo = MAPALGO_Polygon};
	var x = map.Wdt / 2;
	var y = map.Hgt / 2;
	island.X = [x-size/3, x-size/2, x-size/3, x-size/6, x+size/6, x+size/3, x+size/2, x+size/3];
	island.Y = [y-size/6, y, y+size/3, y+size/6, y+size/6, y+size/3, y, y-size/6];
	
	// Draw the earth patch of the island.
	island = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = [10, 6], Seed = Random(65536), Op = island};
	Draw("Earth", island);
		
	// Overlay a set of materials inside the island.
	DrawIslandMat("Earth-earth_root", island, 4, 30);
	DrawIslandMat("Earth-earth", island, 3, 30);
	DrawIslandMat("Tunnel", island, 3, 10);
	DrawIslandMat("Water", island, 4, 8);
	DrawIslandMat("Gold", island, 3, 6);
	DrawIslandMat("Ore", island, 6, 12);
	DrawIslandMat("Firestone", island, 6, 12);
	DrawIslandMat("Coal", island, 6, 12);
	
	// Draw a top border out of sand and top soil.
	var sand_border = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Border, Op = island, Top = [-1, 2]}, {Algo = MAPALGO_RndChecker, Ratio = 50, Wdt = 4, Hgt = 3}]};
 	var topsoil_border = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Border, Op = island, Top = [-1, 3]}, {Algo = MAPALGO_RndChecker, Ratio = 40, Wdt = 4, Hgt = 2}]};
	Draw("Sand", sand_border);
	Draw("Earth-earth_root", topsoil_border);	
	
	// Draw a bottom border out of granite and rock (or everrock on insane).
	var granite_border = {Algo = MAPALGO_Border, Op = island, Bottom = [-4, 3]};
	Draw(["Rock", "Granite", "Everrock"][SCENPAR_Difficulty - 1], granite_border);
	var rock_border = {Algo = MAPALGO_RndChecker, Ratio = 25, Wdt = 2, Hgt = 2};
	Draw(["Granite", "Rock", "Rock"][SCENPAR_Difficulty - 1], {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
	Draw(["Granite", "Rock", "Granite"][SCENPAR_Difficulty - 1], {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
	
	// Draw some gems attached at the bottom of the island.
	var full_island = {Algo = MAPALGO_Or, Op = [island, granite_border]};
	var rect = [x - size / 2, y - size / 3, size / 2, 3 * size / 4];
	DrawGems("Ruby", rect, 3, map, full_island);
	rect = [x, y - size / 3, size / 2, 3 * size / 4];
	DrawGems("Amethyst", rect, 3, map, full_island);
	return;
}

// Draws a smaller island at the specified location if the location rectangle is free, returns whether succeeded.
public func DrawIsland(proplist map, int x, int y, int wdt, int hgt, array mats)
{
	// Don't draw an island if there is already something nearby.
	var rect = [x - wdt, y - 3 * hgt / 2, 2 * wdt, 3 * hgt];
	if (GetPixelCount("Solid", rect) > 0)
		return false;
	
	// An island is just an ellipse with turbulence.
	var island = {Algo = MAPALGO_Ellipsis, X = x, Y = y, Wdt = wdt / 2, Hgt = hgt / 2};
	island = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = [6, 12], Seed = Random(65536), Op = island};
	Draw("Earth", island);
	
	// Overlay a set of materials inside the island.
	DrawIslandMat("Earth-earth_root", island, 4, 30);
	DrawIslandMat("Earth-earth", island, 3, 30);
	DrawIslandMat("Tunnel", island, 3, 10);
	for (var mat in mats)
	{
		DrawIslandMat(mat, island, 4, 18);
		DrawIslandMat(mat, island, 6, 12);
	}
		
	// Draw a top border out of sand and top soil.
	var sand_border = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Border, Op = island, Top = [-1,2]}, {Algo = MAPALGO_RndChecker, Ratio = 50, Wdt = 4, Hgt = 3}]};
 	var topsoil_border = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Border, Op = island, Top = [-1,3]}, {Algo = MAPALGO_RndChecker, Ratio = 40, Wdt = 4, Hgt = 2}]};
	Draw("Sand", sand_border);
	Draw("Earth-earth", topsoil_border);	
	
	// Draw a bottom border out of granite and rock (or everrock on insane).
	var granite_border = {Algo = MAPALGO_Border, Op = island, Bottom = [-2,3]};
	Draw(["Rock", "Granite", "Everrock"][SCENPAR_Difficulty - 1], granite_border);
	var rock_border = {Algo = MAPALGO_RndChecker, Ratio = 20, Wdt = 2, Hgt = 2};
	Draw(["Granite", "Rock", "Granite"][SCENPAR_Difficulty - 1], {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
	Draw(["Granite", "Rock", "Granite"][SCENPAR_Difficulty - 1], {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
		
	// Draw some gems attached at the bottom of the island.
	var gem = ["Ruby", "Amethyst"][Random(2)];
	var full_island = {Algo = MAPALGO_Or, Op = [island, granite_border]};
	DrawGems(gem, rect, 3, map, full_island);
	return true;
}

// Looks for a location at the bottom of a sky islands and places some gems.
public func DrawGems(string gem_mat, array rect, int size, proplist map, proplist island)
{
	// Adapt rect to find at least a spot 8 * MapZoom pixel distance from the map borders.
	rect[2] -= Max(0, 8 - rect[0]); rect[0] = Max(8, rect[0]); // Left boundary.
	rect[2] = Min(rect[2], map.Wdt - rect[0] - 8); // Right boundary.
	
	var low_spot = {X = rect[0], Y = rect[1]};
	for (var i = 0; i < 250; i++)
	{
		var spot = {};
		this->FindPosition(spot, "Solid", rect);
		if (spot.Y > low_spot.Y)
		{
			low_spot = spot;
		}
	}
	
	// Sometimes draw a large patch of tunnel behind the gems.
	if (!Random(3))
	{
		var gem_tunnel = {Algo = MAPALGO_Ellipsis, X = low_spot.X, Y = low_spot.Y + 2, Wdt = size * 3, Hgt = 2 * size};
		gem_tunnel = {Algo = MAPALGO_And, Op = [gem_tunnel, {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Lines, X = 1, Y = 0, OffX = Random(6), Distance = RandomX(4, 6)}}]};
		gem_tunnel = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 14, Scale = 8, Seed = Random(65536), Op = gem_tunnel};
		gem_tunnel = {Algo = MAPALGO_And, Op = [gem_tunnel, {Algo = MAPALGO_Not, Op = island}]};
		Draw("Tunnel", gem_tunnel);
	}
	
	// Draw the gems.
	var gems = {Algo = MAPALGO_Ellipsis, X = low_spot.X, Y = low_spot.Y + 1, Wdt = size - 1, Hgt = size};
	gems = {Algo = MAPALGO_Turbulence, Amplitude = 5, Scale = 5, Iterations = 2, Op = gems};
	Draw(gem_mat, gems);
	
	// Some rock/granite/everrock border above the gems to make it harder to reach.
	var gem_border = {Algo = MAPALGO_Border, Top = -4, Op = gems};
	Draw(["Rock", "Granite", "Everrock"][SCENPAR_Difficulty - 1], gem_border);
	return;
}

// Draws some material inside an island.
public func DrawIslandMat(string mat, proplist onto_mask, int speck_size, int ratio)
{
	if (!speck_size)
		speck_size = 3;
	if (!ratio)
		ratio = 20;
	// Use random checker algorithm to draw patches of the material. 
	var rnd_checker = {Algo = MAPALGO_RndChecker, Ratio = ratio, Wdt = speck_size, Hgt = speck_size};
	rnd_checker = {Algo = MAPALGO_Turbulence, Iterations = 4, Op = rnd_checker};
	var mask_border = {Algo = MAPALGO_Border, Op = onto_mask, Wdt = 3};
	var algo = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Xor, Op = [onto_mask, mask_border]}, rnd_checker]};
	Draw(mat, algo);
	return;
}
