1 /**
2 	Cave
3 	Creates a nice cave.
4 */
5 
6 /*
7 	Randomly places a cave without a border unless specified otherwise.
8 
9 	Custom properties are:
10 
11 	width, height:
12 		size of the cave's bounding box
13 	borderwidth, borderheight:
14 		thickness of the border
15 	bordersize:
16 		implicit borderwidth and borderheight
17 	bordermat:
18 		material of the border, f.e. "Rock"
19 	bordertex:
20 		texture of the border, f.e. "rock_cracked"
21 
22 */
Place(int amount,proplist area,proplist settings)23 public func Place(int amount, proplist area, proplist settings)
24 {
25 /*
26 	var caves = Landscape_Cave->Place(1, nil, {width = 100, height = 50, borderheight = 5, bordermat = "Earth", bordertex = "earth_topSoil" } );
27 	if (GetLength(caves) == 0) FatalError("No cave placed!");
28 */
29 	var caves = [];
30 	amount = amount ?? ((LandscapeHeight() * LandscapeWidth()) / 1000);
31 
32 	var width = settings.width ?? 100;
33 	var height = settings.height ?? 100;
34 	var realwidth = 50, realheight = 50;
35 
36 	if(width < height)
37 	{
38 		var aspect = (100 * width) / height;
39 		realwidth = (aspect * realheight) / 100;
40 	}
41 	else
42 	{
43 		var aspect = (100 * height) / width;
44 		realheight = (aspect * realwidth) / 100;
45 	}
46 	var x = (100 - realwidth) / 2;
47 	var y = (100 - realheight) / 2;
48 
49 	var borderstring = "";
50 	if (settings.bordersize || settings.borderwidth || settings.borderheight)
51 	{
52 		var bordermat = settings.bordermat ?? "Rock";
53 		var bordertex = settings.bordertex ?? "rock";
54 		var borderwidth = settings.borderwidth ?? settings.bordersize ?? 0;
55 		var borderheight = settings.borderheight ?? settings.bordersize ?? 0;
56 		borderstring = Format("overlay { mat = %s; tex = %s; algo = border; a = %d; b = %d; loosebounds = 1; };", bordermat, bordertex, borderwidth, borderheight);
57 	}
58 
59 	var map = Format("overlay { x = %d; y = %d; wdt = %d; hgt = %d; mat = Tunnel; loosebounds = 1; turbulence = 500; %s };", x, y, realwidth, realheight, borderstring);
60 
61 	var failsafe = 100;
62 
63 	while((--failsafe > 0) && amount > 0)
64 	{
65 		var spot = FindLocation(Loc_Solid(), Loc_Func(Landscape_Cave.IsGoodCaveSpot), Loc_InArea(area));
66 		if (!spot) continue;
67 
68 		DrawMap(spot.x - width, spot.y - height, 2 * width, 2 * height, Format("map Cave { %s };", map));
69 		var cave = CreateObjectAbove(Landscape_Cave, spot.x, spot.y, NO_OWNER);
70 		PushBack(caves, cave);
71 
72 		// project free objects down to the ground
73 		for (var obj in FindObjects(Find_InRect(spot.x - width, spot.y - height, 2 * width, 2 * height), Find_Category(C4D_Object)))
74 		{
75 			var originaly = obj->GetY();
76 			var max = height;
77 			while ((!obj->GetContact(-1, CNAT_Bottom)) && !obj->Stuck() && (--max > 0))
78 			{
79 				obj->SetPosition(obj->GetX(), obj->GetY() + 1);
80 			}
81 			if (max <= 0) obj->SetPosition(obj->GetX(), originaly);
82 		}
83 
84 		--amount;
85 	}
86 
87 	return caves;
88 }
89 
IsGoodCaveSpot(int x,int y)90 func IsGoodCaveSpot(int x, int y)
91 {
92 	// cave must be "far" underground!
93 	var no_sky_distance = 200;
94 	for (var yd = 0; yd <= no_sky_distance; yd += 10)
95 		if (GBackSky(x, y - yd)) return false;
96 
97 	var cave = FindObjects(Find_ID(Landscape_Cave), Sort_Distance(x, y));
98 	if (GetLength(cave) == 0) return true;
99 	cave = cave[0];
100 	return Distance(x, y, cave->GetX(), cave->GetY()) > 100;
101 }
102