1 /**
2 	Blue lake
3 	Dynamic map with a big lake containing islands of material
4 	Plus lava basins with gems at the bottom
5 	Parts adapted from Gem Grabbers by Maikel
6 
7 	@authors Sven2
8 */
9 
10 #include Library_Map
11 
12 // zoomed coordinates for scenario script
13 static main_island_x, main_island_y;
14 static goal_platform_x, goal_platform_y;
15 
16 // set after intro to force map creation
17 // g_intro_done;
18 
19 // Called be the engine: draw the complete map here.
InitializeMap(proplist map)20 public func InitializeMap(proplist map)
21 {
22 	if (!g_intro_done && !SCEN_TEST) return true;
23 	Resize(300,400);
24 	this.sea_y = 50;
25 	this.ground_y = 350;
26 	this.map_zoom = 7;
27 	main_island_x = this.Wdt/2 * this.map_zoom;
28 	main_island_y = this.sea_y * this.map_zoom;
29 
30 	Draw("Water", nil, [0,this.sea_y,this.Wdt,this.Hgt]);
31 	DrawMainIsland(80);
32 	DrawGround();
33 
34 	// Regular resource islands
35 	DrawSecondaryIslands(3, 15, [["Ore", 50], ["Coal", 40]], true);
36 	DrawSecondaryIslands(10, 6, [["Firestone", 70]], false);
37 	DrawSecondaryIslands(3, 8, [["Gold", 40]], true);
38 
39 	// Amethyst islands
40 	var i=0, imod=Random(2);
41 	while (i<3 || GetPixelCount("Amethyst")<15)
42 	{
43 		DrawSecondaryIsland(8, [["Amethyst", 70]], true, [0, this.Wdt-70][(i+imod)%2], 70, this.sea_y+50);
44 		++i;
45 	}
46 
47 	FixLiquidBorders("Earth");
48 
49 	// Ensure that left and right side are always open because they're used for water refill
50 	Draw("Sky", nil, [0,0,1,this.sea_y]);
51 	Draw("Sky", nil, [this.Wdt-1,0,1,this.sea_y]);
52 	Draw("Water", nil, [0,this.sea_y,1,70]);
53 	Draw("Water", nil, [this.Wdt-1,this.sea_y,1,70]);
54 
55 	// Top level of water has sky background
56 	Draw("^Water", Duplicate("Water"), [0,this.sea_y,this.Wdt,11]);
57 
58 	// Return true to tell the engine a map has been successfully created.
59 	return true;
60 }
61 
62 // Draws the main island with all basic resources
DrawMainIsland(int size)63 private func DrawMainIsland(int size)
64 {
65 	// Shape of the main island. Shape taken from Gem Grabbers.
66 	var island_algo = {Algo = MAPALGO_Polygon};
67 	var x = this.Wdt / 2;
68 	var y = this.sea_y;
69 	island_algo.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];
70 	island_algo.Y = [y-size/6, y, y+size/3, y+size/6, y+size/6, y+size/3, y, y-size/6];
71 
72 	// Draw the earth patch of the island.
73 	island_algo = {Algo = MAPALGO_Turbulence, Iterations = 4, Op = island_algo};
74 	var island = CreateLayer();
75 	island->Draw("Earth", island_algo);
76 
77 	// Draw goal platform shape
78 	while (island->GetPixel(x,y)) ++x; // Find right side of island at sea level
79 	var platform_algo = {Algo = MAPALGO_Polygon};
80 	platform_algo.X = [x-5,x+14,x+14,x+7,x  ,x-5];
81 	platform_algo.Y = [y  ,y   ,y+ 1,y+2,y+4,y  ];
82 	island->Draw("Earth", platform_algo);
83 
84 	// Preserve drawn island shape for border algorithms
85 	var island_shape = island->Duplicate();
86 
87 	// Overlay a set of materials inside the island.
88 	DrawIslandMat("Earth-earth_root", island, 4, 30, true);
89 	DrawIslandMat("Earth-earth", island, 3, 30, true);
90 	DrawIslandMat("Tunnel", island, 3, 10, true);
91 	//DrawIslandMat("Water", island, 4, 8);
92 	//DrawIslandMat("Gold", island, 3, 6);
93 	DrawIslandMat("Ore", island, 6, 18, true);
94 	DrawIslandMat("Coal", island, 6, 18, true);
95 	DrawIslandMat("Firestone", island, 6, 12, true);
96 
97 	// Draw a top border out of sand and top soil.
98 	var sand_border = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Border, Op = island_shape, Top = [-1,2]}, {Algo = MAPALGO_RndChecker, Ratio = 50, Wdt = 4, Hgt = 3}]};
99  	var topsoil_border = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Border, Op = island_shape, Top = [-1,3]}, {Algo = MAPALGO_RndChecker, Ratio = 40, Wdt = 4, Hgt = 2}]};
100 	island->Draw("Sand", sand_border);
101 	island->Draw("Earth-earth", topsoil_border);
102 
103 	// Draw a bottom border out of granite and rock.
104 	var granite_border = {Algo = MAPALGO_Border, Op = island_shape, Bottom = [-4,3]};
105 	island->Draw("Granite", granite_border);
106 	var rock_border = {Algo = MAPALGO_RndChecker, Ratio = 20, Wdt = 2, Hgt = 2};
107 	island->Draw("Rock", {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
108 	island->Draw("Rock-rock", {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
109 
110 	// Draw goal platform
111 	island->Draw("Sky", nil, [x,y-10,14,10]);
112 	island->Draw("Brick", nil, [x,y,14,2]);
113 	goal_platform_x = (x+7)*this.map_zoom;
114 	goal_platform_y = y    *this.map_zoom;
115 
116 	// Draw island onto main map
117 	Blit(island);
118 
119 	return true;
120 }
121 
122 // Draws multiple underwater resource islands
DrawSecondaryIslands(int n,...)123 private func DrawSecondaryIslands(int n, ...)
124 {
125 	for (var i=0; i<n; ++i) DrawSecondaryIsland(...);
126 	return true;
127 }
128 
129 // Draws underwater resource island
DrawSecondaryIsland(int size,array materials,bool has_border,int xmin,int xwdt,int ymin)130 private func DrawSecondaryIsland(int size, array materials, bool has_border, int xmin, int xwdt, int ymin)
131 {
132 	// Find a free spot underwater
133 	var x,y;
134 	var border = size; // left and right border
135 	if (!xwdt) xwdt = this.Wdt;
136 	if (!ymin) ymin = this.sea_y;
137 	var i_tries = 200;
138 	while (i_tries--)
139 	{
140 		var x = Random(xwdt - border*2) + border + xmin;
141 		var y = Random(this.ground_y - ymin - size) + ymin + size/2;
142 		if (GetPixelCount("Solid", [x-size,y-size,size,size])) continue;
143 		break;
144 	}
145 
146 	// Shape of the resource island
147 	var island_algo = {Algo = MAPALGO_Ellipsis, X=x, Y=y, Wdt=size, Hgt=size};
148 	island_algo = {Algo = MAPALGO_Turbulence, Amplitude = [20,5], Iterations = 3, Op = island_algo};
149 	var island = CreateLayer();
150 	island->Draw("Earth", island_algo);
151 	var island_shape = island->Duplicate();
152 
153 	DrawIslandMat("Earth-earth_spongy", island, 4, 30);
154 	DrawIslandMat("Earth-earth", island, 3, 30);
155 
156 	// Overlay a set of materials inside the island.
157 	for (var mat in materials)
158 	{
159 		DrawIslandMat(mat[0], island, 3, mat[1], has_border);
160 	}
161 
162 	// Draw a border out of granite and rock.
163 	if (has_border)
164 	{
165 		var island_shape = island->Duplicate();
166 		var granite_border = {Algo = MAPALGO_Border, Op = island_shape, Top = [-2,2]};
167 		island->Draw("Granite", granite_border);
168 		var rock_border = {Algo = MAPALGO_RndChecker, Ratio = 20, Wdt = 2, Hgt = 2};
169 		island->Draw("Rock", {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
170 		island->Draw("Rock-rock", {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
171 	}
172 
173 	// Draw island onto main map
174 	Blit(island);
175 
176 	return true;
177 }
178 
DrawGround()179 private func DrawGround()
180 {
181 	// Bottom of the sea
182 	var ground_algo = { Algo = MAPALGO_Rect, X=-100, Y=this.ground_y, Wdt=this.Wdt+200, Hgt=this.Hgt-this.ground_y+1000 };
183 	ground_algo = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = [10,100], Scale = 20, Op = ground_algo };
184 	var ground2_algo = { Algo = MAPALGO_Rect, X=-100, Y=this.Hgt-10, Wdt=this.Wdt+200, Hgt=this.Hgt-this.ground_y+1000 };
185 	ground2_algo = {Algo = MAPALGO_Turbulence, Iterations = 2, Amplitude = 10, Scale = 30, Op = ground2_algo };
186 	var ground = CreateLayer();
187 	// Ensure lots of earth
188 	while (true)
189 	{
190 		ground->Draw("Earth", ground_algo);
191 		ground->Draw("Granite", ground2_algo);
192 		if (ground->GetPixelCount("Earth") > 10000) break;
193 	}
194 	ground->Draw("DuroLava", {Algo=MAPALGO_Turbulence, Amplitude=10, Scale=20, Iterations=3, Op={Algo=MAPALGO_And, Op=[ground->Duplicate("Granite"), {Algo = MAPALGO_RndChecker, Ratio=50, Wdt=30, Hgt=2}]}});
195 	// Granite/Rock top border
196 	ground->Draw("Granite", {Algo = MAPALGO_Turbulence, Amplitude = 5, Iterations = 1, Op = {Algo = MAPALGO_Border, Op = ground->Duplicate(), Top= [-2,2]}});
197 	ground->Draw("Rock", {Algo=MAPALGO_And, Op=[ground->Duplicate("Granite"), {Algo = MAPALGO_RndChecker, Ratio = 40, Wdt = 2, Hgt = 2}]});
198 	// Alterations in earth material
199 	DrawIslandMat("Earth-earth_spongy", ground, 12, 60, false);
200 	DrawIslandMat("Earth-earth", ground, 8, 60, false);
201 	// Gem spots
202 	var gem_spots = CreateLayer();
203 	var earth_mats = CreateMatTexMask("Earth");
204 	var i=0;
205 	while (i<3 || gem_spots->GetPixelCount("Ruby") < 15)
206 	{
207 		var gem_mat = "Ruby";
208 		// Find an earth spot
209 		var pos = {X=Random(this.Wdt), Y=this.Hgt/2+Random(this.Hgt/2)};
210 		ground->FindPosition(pos, "Earth");
211 		// Find center of this earth area
212 		var x=pos.X, y=pos.Y;
213 		var x0=x-1, x1=x+1, y0=y-1, y1=y+1;
214 		while (earth_mats[ground->GetPixel(x,y0)]) --y0;
215 		while (earth_mats[ground->GetPixel(x,y1)]) ++y1;
216 		y=Min((y0+y1)/2, this.Hgt-6);
217 		while (earth_mats[ground->GetPixel(x0,y)]) --x0;
218 		while (earth_mats[ground->GetPixel(x1,y)]) ++x1;
219 		x=(x0+x1)/2;
220 		var size = 9;
221 		// Lava basin here
222 		var lava_algo = {Algo = MAPALGO_Ellipsis, X=x, Y=y, Wdt=size, Hgt=size};
223 		lava_algo = {Algo = MAPALGO_Turbulence, Amplitude = 5, Iterations = 5, Op = lava_algo};
224 		gem_spots->Draw("DuroLava", lava_algo);
225 		// Gems at bottom center
226 		y += 2;
227 		size = 3;
228 		var gem_algo = {Algo = MAPALGO_Ellipsis, X=x, Y=y, Wdt=size, Hgt=size};
229 		gem_algo = {Algo = MAPALGO_Turbulence, Amplitude = 3, Iterations = 1, Op = gem_algo};
230 		gem_spots->Draw(gem_mat, gem_algo);
231 		// Draw to map
232 		ground->Blit(gem_spots);
233 		++i;
234 	}
235 	// Lava basins surrounded by granite
236 	ground->Draw("Rock", {Algo=MAPALGO_And, Op=[{Algo=MAPALGO_Not, Op=gem_spots}, {Algo = MAPALGO_Turbulence, Amplitude = 5, Iterations = 5, Op = {Algo = MAPALGO_Border, Op = gem_spots, Wdt=-4}}]});
237 	ground->Draw("Granite", {Algo = MAPALGO_Border, Op = gem_spots, Wdt=-1});
238 	// Lots of rocks
239 	DrawIslandMat("Rock", ground, 2, 20, false);
240 	DrawIslandMat("Rock", ground, 2, 20, false);
241 	// And some lava
242 	DrawIslandMat("DuroLava", ground, 2, 20, false);
243 	// Other materials (rare)
244 	DrawIslandMat("Ore", ground, 12, 8, false);
245 	DrawIslandMat("Coal", ground, 12, 8, false);
246 	DrawIslandMat("Gold", ground, 12, 8, false);
247 	DrawIslandMat("Firestone", ground, 12, 8, false);
248 	Blit(ground);
249 	return true;
250 }
251 
252 // Draws some material inside an island.
DrawIslandMat(string mat,proplist onto_mask,int speck_size,int ratio,has_border)253 private func DrawIslandMat(string mat, proplist onto_mask, int speck_size, int ratio, has_border)
254 {
255 	if (!speck_size)
256 		speck_size = 3;
257 	if (!ratio)
258 		ratio = 20;
259 	// Use random checker algorithm to draw patches of the material.
260 	var rnd_checker = {Algo = MAPALGO_RndChecker, Ratio = ratio, Wdt = speck_size, Hgt = speck_size};
261 	rnd_checker = {Algo = MAPALGO_Turbulence, Iterations = 4, Op = rnd_checker};
262 	var algo;
263 	if (has_border)
264 	{
265 		var mask_border = {Algo = MAPALGO_Border, Op = onto_mask, Wdt = 3};
266 		algo = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Xor, Op = [onto_mask->Duplicate("Earth"), mask_border]}, rnd_checker]};
267 	}
268 	else
269 	{
270 		algo = {Algo = MAPALGO_And, Op = [onto_mask->Duplicate("Earth"), rnd_checker]};
271 	}
272 	onto_mask->Draw(mat, algo);
273 
274 	return true;
275 }
276