File: Script.c

package info (click to toggle)
openclonk 7.0-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 145,828 kB
  • ctags: 33,094
  • sloc: cpp: 163,891; ansic: 82,846; xml: 29,876; python: 1,203; php: 767; makefile: 138; sh: 77
file content (256 lines) | stat: -rwxr-xr-x 9,341 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*--
		Library_Map
		Authors: Sven2
	
		Utility functions for map drawing in InitializeMap().
--*/

// Returns p if p is an int. If p is an array of two ints, returns a
// random value between both (assuming p[1]>p[0])
func EvalIntPar(p) { if (GetType(p) == C4V_Array) return p[0]+Random(p[1]-p[0]); return p; }

// Returns p if p is an int. If p is an array of two ints, returns the
// medium value of both
func EvalIntParM(p) { if (GetType(p) == C4V_Array) return (p[0]+p[1])/2; return p; }

func DrawVaried(string mat, proplist algo, array rect, vary_mats)
{
	// Draw material and put rndchecker variations of other materials on it
	if (GetType(vary_mats) != C4V_Array || (GetLength(vary_mats)==3 && GetType(vary_mats[1])==C4V_Int)) vary_mats = [vary_mats];
	var ratio = 100/(GetLength(vary_mats)+1);
	var main_shape = this->CreateLayer();
	main_shape->Draw(mat, algo, rect);
	this->Blit(main_shape, rect);
	for (var vary_def in vary_mats)
	{
		var sx=3,sy=3;
		if (GetType(vary_def) == C4V_Array)
		{
			sx=vary_def[1]; sy = vary_def[2];
			vary_def = vary_def[0];
		}
		var rand_algo = {Algo=MAPALGO_RndChecker, Ratio=ratio, Wdt=sx, Hgt=sy};
		var turb_algo = {Algo=MAPALGO_Turbulence, Amplitude=12, Scale=8, Op=rand_algo};
		this->Draw(vary_def, {Algo=MAPALGO_And, Op=[main_shape, turb_algo]});
	}
	return main_shape;
}

func DrawSpots(string mat, int num, sizex, sizey, array rect, inmat, vary_mats)
{
	// Default parameters
	if (!inmat) inmat="Earth";
	if (!sizex) sizex = [5, 20];
	if (!sizey) sizey = [5, 7];
	if (!num) num=Max(this->GetPixelCount(inmat, rect) / (EvalIntParM(sizex)*EvalIntParM(sizey)*10), 1);
	// Draw num spots
	var spot = {Algo=MAPALGO_Ellipsis};
	while (num--)
	{
		if (!this->FindPosition(spot, inmat, rect)) break;
		var mask = this->Duplicate(inmat);
		spot.Wdt = EvalIntPar(sizex)/2;
		spot.Hgt = EvalIntPar(sizey)/2;
		var algo = {Algo=MAPALGO_And, Op=[mask, {Algo=MAPALGO_Turbulence, Amplitude=Max(spot.Wdt, spot.Hgt), Scale=Max(spot.Wdt, spot.Hgt), Op=spot}]};
		if (vary_mats)
			DrawVaried(mat, algo, rect, vary_mats);
		else
			this->Draw(mat, algo, rect);
	}
	return true;
}

func DrawCoal(int num, array rect) { return DrawSpots("Coal", num, [20,60], [4,8], rect, nil); }
func DrawFirestone(int num, array rect) { return DrawSpots("Firestone", num, [20,60], [8,12], rect, nil); }
func DrawOre(int num, array rect) { return DrawSpots("Ore", num, [8,12], [14,20], rect, nil); }
func DrawGold(int num, array rect) { return DrawSpots("Gold", num, [10,14], [10,14], rect, nil); }
func DrawRock(int num, array rect) { return DrawSpots("Rock-rock", num, [20,80], [6,8], rect, nil, [["Rock-rock", 3,10], ["Granite", 6,2]]); }

// Draws the given material onto an existing mask with given size and ratio.
public func DrawMaterial(string mat, proplist onto_mask, speck_size, int ratio)
{
	// Defaults and check whether speck size is an array.
	if (!speck_size)
		speck_size = 4;
	if (!ratio)
		ratio = 15;
	if (GetType(speck_size) != C4V_Array) 
		speck_size = [speck_size, speck_size];
	// Use random checker algorithm to draw patches of the material. 
	var rnd_checker = {Algo = MAPALGO_RndChecker, Ratio = ratio, Wdt = speck_size[0], Hgt = speck_size[1]};
	rnd_checker = {Algo = MAPALGO_Turbulence, Iterations = 4, Op = rnd_checker};
	var material_mask = {Algo = MAPALGO_And, Op = [onto_mask, rnd_checker]};
	// Draw the material onto the calling map object.
	this->Draw(mat, material_mask);
	return;
}

func DrawWaterVeins(int num, array rect)
{
	while (num--) DrawLiquidVein("Water", 3, 5, rect);
	return true;
}

func DrawLiquidVein(string mat, int wdt, int spread, array rect, inmat)
{
	if (!rect) rect = [0,0,this.Wdt, this.Hgt];
	if (!inmat) inmat="Earth";
	var mask = this->Duplicate(inmat);
	var x1 = rect[0]-rect[2]+Random(rect[2]*3);
	var y1 = rect[1]-rect[3]+Random(rect[3]*3);
	var x2 = rect[0]+Random(rect[2]);
	var y2 = rect[1]+Random(rect[3]);
	var water = {Algo=MAPALGO_Polygon, X=[x1,x2], Y=[y1,y2], Wdt=wdt};
	var water_rand = {Algo=MAPALGO_Turbulence, Amplitude=30, Scale=30, Op=water};
	var water_rand2 = {Algo=MAPALGO_Turbulence, Amplitude=spread*2, Scale=2, Op=water_rand};
	this->Draw(mat, {Algo=MAPALGO_And, Op=[mask, water_rand2]});
	return true;
}

func DrawRegularGround(array rect, yoff, turbulence)
{
	// Draw regular (boring) ground level
	if (!rect) rect = [0,0,this.Wdt, this.Hgt];
	if (GetType(yoff) == C4V_Nil) yoff = rect[3]/4;
	if (GetType(turbulence) == C4V_Nil) turbulence = 30;
	var ground_rect = {Algo=MAPALGO_Rect, X=-100, Y=rect[1]+yoff, Wdt=rect[0]+rect[2]+200, Hgt=rect[3]+100};
	var ground_algo = {Algo=MAPALGO_Turbulence, Amplitude=turbulence, Scale=30, Op=ground_rect};
	var earth_shape = DrawVaried("Earth-earth", ground_algo, rect, [["Earth-earth_root", 3,10], ["Earth-earth_spongy", 6,2]]);
	var top1 = {Algo=MAPALGO_Border, Top=[-10, 3], Op=earth_shape};
	var top2 = {Algo=MAPALGO_Border, Top=[-10, 1], Op=earth_shape};
	this->Draw("Earth-earth", {Algo=MAPALGO_And, Op=[earth_shape, {Algo=MAPALGO_Turbulence, Amplitude=4, Scale=10, Op=top1}]});
	this->Draw("Earth-earth", {Algo=MAPALGO_And, Op=[earth_shape, {Algo=MAPALGO_Turbulence, Amplitude=4, Scale=10, Op=top2}]});
	return true;
}

func FixLiquidBorders(border_material, lava_border_material)
{
	// Makes sure liquids bordering other liquids as well as liquids
	// bordering background materials are surrounded by fix_material
	// Default border materials
	if (!border_material) border_material = "Earth-earth";
	if (!lava_border_material) lava_border_material = "Rock";
	// Find liquid-to-background borders
	var liquids = this->Duplicate("Liquid");
	var liquid_borders = {Algo=MAPALGO_Border, Op=liquids, Wdt=-1, Top=0 };
	var background = this->Duplicate("Background");
	background->Draw("Sky", {Algo=MAPALGO_Not, Op=this});
	this->Draw(border_material, {Algo=MAPALGO_And, Op=[liquid_borders, background]});
	// Put lava on top of other liquids
	var lava_borders = {Algo=MAPALGO_Border, Op=this->Duplicate(["Lava", "DuroLava"])};
	this->Draw(lava_border_material, {Algo=MAPALGO_And, Op=[lava_borders, liquids]});
	// Put acid on top of water
	var acid_borders = {Algo=MAPALGO_Border, Op=this->Duplicate("Acid")};
	this->Draw(border_material, {Algo=MAPALGO_And, Op=[acid_borders, liquids]});
	return true;
}

func DrawPlatform(string material, int x0, int y0, int wdt, int hgt_up, int hgt_down)
{
	var ground_mask = this->Duplicate("~Background");
	for (var x=x0; x<x0+wdt; ++x)
	{
		// Adjust materials bottom
		var y, px;
		for (y=y0+1; y<=y0+hgt_down; ++y)
		{
			px = ground_mask->GetPixel(x,y);
			if (px) break;
		}
		if (px) for (--y; y>y0; --y) this->SetPixel(x,y,px);
	}
	// Free top
	if (hgt_up) this->Draw("Sky", nil, [x0,y0-hgt_up,wdt,hgt_up]);
	// Draw platform itself
	if (material) this->Draw(material, nil, [x0,y0,wdt,1]);
}

func FindBottomPeaks(array rect, int min_dx)
{
	// Find downwards peaks in bottom-most nonzero pixels in rect
	// Peaks are minimum min_dx apart horizontally
	var x1,y1,x2,y2;
	if (rect)
		{ x1=rect[0]; y1=rect[1]; x2=x1+rect[2]; y2=y1+rect[3]; }
	else
		{ x2=this.Wdt; y2=this.Hgt; }
	var last_y = y2+1, last_dy = 0, num_dy_0 = 0, last_peak_x = -min_dx-1;
	var peaks = [];
	for (var x=x1; x<x2; ++x)
	{
		var y = y2;
		while (!this->GetPixel(x,y)) if (y1>=--y) break;
		var dy = y - last_y;
		if (!dy)
		{
			++num_dy_0;
		}
		else
		{
			if (dy < 0 && last_dy > 0)
			{
				var peak_x = x-1-num_dy_0/2;
				if (num_dy_0%2 && !Random(2)) --peak_x;
				if (peak_x-last_peak_x < min_dx)
				{
					if (!Random(2)) peaks[GetLength(peaks)-1] = {X=peak_x, Y=last_y};
				}
				else
				{
					peaks[GetLength(peaks)] = {X=peak_x, Y=last_y};
				}
				last_peak_x = peaks[GetLength(peaks)-1].X;
			}
			num_dy_0 = 0;
			last_dy = dy;
		}
		last_y = y;
	}
	return peaks;
}

func FillLiquid(string mat, int x, int y, max_wdt, int max_hgt)
{
	// Fill area downwards and sideways of given x and y with mat
	// Stay within rectangle x-max_wdt and x+max_wdt horizontally and within y and y+max_hgt vertically
	var background_mask = this->CreateMatTexMask("Background");
	var open_ranges = [[x,x]], n_open = 1;
	max_hgt = BoundBy(max_hgt, 0, this.Hgt-y);
	if (GetType(max_wdt) != C4V_Array) max_wdt = [max_wdt,max_wdt];
	var min_x1 = Max(x-max_wdt[0]), min_x2 = Max(x-max_wdt[1]);
	var max_x1 = Min(x+max_wdt[0], this.Wdt-1), max_x2 = Min(x+max_wdt[1], this.Wdt-1);
	var min_x = (min_x1+min_x2)/2, max_x = (max_x1+max_x2)/2;
	var n_pix_set = 0;
	while (n_open && max_hgt)
	{
		var next_ranges = [], n_next = 0;
		x = -1;
		for (var range in open_ranges)
		{
			var x1=range[0], x2=range[1];
			if (x>x1) continue; // two or more paths merged
			while (x1>min_x && background_mask[this->GetPixel(x1-1,y)]) --x1;
			while (x2<max_x && background_mask[this->GetPixel(x2+1,y)]) ++x2;
			var below_was_background = false;
			for (x=x1; x<=x2; ++x)
			{
				this->SetPixel(x,y,mat); ++n_pix_set;
				var below_is_background = background_mask[this->GetPixel(x,y+1)];
				if (below_is_background)
				{
					if (!below_was_background)
						next_ranges[n_next++] = [x,x];
					else
						++next_ranges[n_next-1][1];
				}
				below_was_background = below_is_background;
			}
		}
		open_ranges = next_ranges;
		n_open = n_next;
		++y; --max_hgt;
		min_x = BoundBy(min_x+Random(3)-1, min_x1,min_x2);
		max_x = BoundBy(max_x+Random(3)-1, max_x1,max_x2);
	}
	return n_pix_set;
}