1/*
2 * LegacyClonk
3 *
4 * Copyright (c) 1998-2000, Matthes Bender (RedWolf Design)
5 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16
17/* Create map from dynamic landscape data in scenario */
18
19#include <C4Include.h>
20#include <C4Map.h>
21
22#include <C4Random.h>
23#include <C4Texture.h>
24#include <C4Group.h>
25
26#include <Bitmap256.h>
27
28#include <numbers>
29
30C4MapCreator::C4MapCreator()
31{
32 Reset();
33}
34
35void C4MapCreator::Reset()
36{
37 MapIFT = 128;
38 MapBuf = nullptr;
39 Exclusive = -1;
40}
41
42void C4MapCreator::SetPix(int32_t x, int32_t y, uint8_t col)
43{
44 // Safety
45 if (!Inside<int32_t>(ival: x, lbound: 0, rbound: MapWdt - 1) || !Inside<int32_t>(ival: y, lbound: 0, rbound: MapHgt - 1)) return;
46 // Exclusive
47 if (Exclusive > -1) if (GetPix(x, y) != Exclusive) return;
48 // Set pix
49 MapBuf->SetPix(iX: x, iY: y, byCol: col);
50}
51
52void C4MapCreator::DrawLayer(int32_t x, int32_t y, int32_t size, uint8_t col)
53{
54 int32_t cnt, cnt2;
55 for (cnt = 0; cnt < size; cnt++)
56 {
57 x += Random(iRange: 9) - 4; y += Random(iRange: 3) - 1;
58 for (cnt2 = Random(iRange: 3); cnt2 < 5; cnt2++)
59 {
60 SetPix(x: x + cnt2, y, col); SetPix(x: x + cnt2 + 1, y: y + 1, col);
61 }
62 }
63}
64
65uint8_t C4MapCreator::GetPix(int32_t x, int32_t y)
66{
67 // Safety
68 if (!Inside<int32_t>(ival: x, lbound: 0, rbound: MapWdt - 1) || !Inside<int32_t>(ival: y, lbound: 0, rbound: MapHgt - 1)) return 0;
69 // Get pix
70 return MapBuf->GetPix(iX: x, iY: y);
71}
72
73void C4MapCreator::Create(CSurface8 *sfcMap,
74 C4SLandscape &rLScape, C4TextureMap &rTexMap,
75 bool fLayers, int32_t iPlayerNum)
76{
77 double fullperiod = 20.0 * std::numbers::pi;
78 uint8_t ccol;
79 int32_t cx, cy;
80
81 // Safeties
82 if (!sfcMap) return;
83 iPlayerNum = BoundBy<int32_t>(bval: iPlayerNum, lbound: 1, rbound: C4S_MaxPlayer);
84
85 // Set creator variables
86 MapBuf = sfcMap;
87 MapWdt = MapBuf->Wdt; MapHgt = MapBuf->Hgt;
88
89 // Reset map (0 is sky)
90 MapBuf->ClearBox8Only(iX: 0, iY: 0, iWdt: MapBuf->Wdt, iHgt: MapBuf->Hgt);
91
92 // Surface
93 ccol = rTexMap.GetIndexMatTex(szMaterialTexture: rLScape.Material, szDefaultTexture: "Smooth") + MapIFT;
94 float amplitude = static_cast<float>(rLScape.Amplitude.Evaluate());
95 float phase = static_cast<float>(rLScape.Phase.Evaluate());
96 float period = static_cast<float>(rLScape.Period.Evaluate());
97 if (rLScape.MapPlayerExtend) period *= (std::min)(a: iPlayerNum, b: C4S_MaxMapPlayerExtend);
98 float natural = static_cast<float>(rLScape.Random.Evaluate());
99 int32_t level0 = (std::min)(a: MapWdt, b: MapHgt) / 2;
100 int32_t maxrange = level0 * 3 / 4;
101 double cy_curve, cy_natural; // -1.0 - +1.0 !
102
103 double rnd_cy, rnd_tend; // -1.0 - +1.0 !
104 rnd_cy = (Random(iRange: 2000 + 1) - 1000) / 1000.0;
105 rnd_tend = (Random(iRange: 200 + 1) - 100) / 20000.0;
106
107 for (cx = 0; cx < MapWdt; cx++)
108 {
109 rnd_cy += rnd_tend;
110 rnd_tend += (Random(iRange: 100 + 1) - 50) / 10000.0;
111 if (rnd_tend > +0.05) rnd_tend = +0.05;
112 if (rnd_tend < -0.05) rnd_tend = -0.05;
113 if (rnd_cy < -0.5) rnd_tend += 0.01;
114 if (rnd_cy > +0.5) rnd_tend -= 0.01;
115
116 cy_natural = rnd_cy * natural / 100.0;
117 cy_curve = sin(x: fullperiod * period / 100.0 * cx / static_cast<double>(MapWdt) +
118 2.0 * std::numbers::pi * phase / 100.0) * amplitude / 100.0;
119
120 cy = level0 + BoundBy(bval: static_cast<int32_t>(maxrange * (cy_curve + cy_natural)),
121 lbound: -maxrange, rbound: +maxrange);
122
123 SetPix(x: cx, y: cy, col: ccol);
124 }
125
126 // Raise bottom to surface
127 for (cx = 0; cx < MapWdt; cx++)
128 for (cy = MapHgt - 1; (cy >= 0) && !GetPix(x: cx, y: cy); cy--)
129 SetPix(x: cx, y: cy, col: ccol);
130 // Raise liquid level
131 Exclusive = 0;
132 ccol = rTexMap.GetIndexMatTex(szMaterialTexture: rLScape.Liquid, szDefaultTexture: "Smooth");
133 int32_t wtr_level = rLScape.LiquidLevel.Evaluate();
134 for (cx = 0; cx < MapWdt; cx++)
135 for (cy = MapHgt * (100 - wtr_level) / 100; cy < MapHgt; cy++)
136 SetPix(x: cx, y: cy, col: ccol);
137 Exclusive = -1;
138
139 // Layers
140 if (fLayers)
141 {
142 // Base material
143 Exclusive = rTexMap.GetIndexMatTex(szMaterialTexture: rLScape.Material, szDefaultTexture: "Smooth") + MapIFT;
144
145 int32_t cnt, clayer, layer_num, sptx, spty;
146
147 // Process layer name list
148 for (clayer = 0; clayer < C4MaxNameList; clayer++)
149 if (rLScape.Layers.Name[clayer][0])
150 {
151 // Draw layers
152 ccol = rTexMap.GetIndexMatTex(szMaterialTexture: rLScape.Layers.Name[clayer], szDefaultTexture: "Rough") + MapIFT;
153 layer_num = rLScape.Layers.Count[clayer];
154 layer_num = layer_num * MapWdt * MapHgt / 15000;
155 for (cnt = 0; cnt < layer_num; cnt++)
156 {
157 // Place layer
158 sptx = Random(iRange: MapWdt);
159 for (spty = 0; (spty < MapHgt) && (GetPix(x: sptx, y: spty) != Exclusive); spty++);
160 spty += 5 + Random(iRange: (MapHgt - spty) - 10);
161 DrawLayer(x: sptx, y: spty, size: Random(iRange: 15), col: ccol);
162 }
163 }
164
165 Exclusive = -1;
166 }
167}
168