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