• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 19015014167

02 Nov 2025 04:28PM UTC coverage: 50.474% (-0.005%) from 50.479%
19015014167

push

github

Flow86
Move EnableCCache include after submodule check

It is in libutil which may not exist or be up to date, so check those first

22504 of 44585 relevant lines covered (50.47%)

33867.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.72
/libs/s25main/mapGenerator/RandomMap.cpp
1
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "mapGenerator/RandomMap.h"
6
#include "mapGenerator/Harbors.h"
7
#include "mapGenerator/HeadQuarters.h"
8
#include "mapGenerator/Islands.h"
9
#include "mapGenerator/Resources.h"
10
#include "mapGenerator/Terrain.h"
11
#include "mapGenerator/TextureHelper.h"
12
#include "mapGenerator/Textures.h"
13

14
#include "lua/GameDataLoader.h"
15
#include "libsiedler2/libsiedler2.h"
16

17
#include <stdexcept>
18

19
namespace rttr::mapGenerator {
20

21
unsigned GetMaximumHeight(const MapExtent& size)
6✔
22
{
23
    const unsigned combinedSize = size.x * size.y;
6✔
24
    if(combinedSize <= 64 * 64)
6✔
25
        return 32;
5✔
26
    else if(combinedSize <= 128 * 128)
1✔
27
        return 64;
1✔
28
    else if(combinedSize <= 256 * 256)
×
29
        return 128;
×
30
    else if(combinedSize <= 512 * 512)
×
31
        return 150;
×
32
    else if(combinedSize <= 1024 * 1024)
×
33
        return 200;
×
34
    else
35
        return 60;
×
36
}
37

38
unsigned GetCoastline(const MapExtent& size)
6✔
39
{
40
    const unsigned combinedSize = size.x * size.y;
6✔
41
    if(combinedSize <= 128 * 128)
6✔
42
        return 1;
6✔
43
    else if(combinedSize <= 512 * 512)
×
44
        return 2;
×
45
    else if(combinedSize <= 1024 * 1024)
×
46
        return 3;
×
47
    else
48
        return 4;
×
49
}
50

51
unsigned GetIslandRadius(const MapExtent& size)
4✔
52
{
53
    const unsigned combinedSize = size.x * size.y;
4✔
54
    if(combinedSize <= 128 * 128)
4✔
55
        return 2;
4✔
56
    else if(combinedSize <= 256 * 256)
×
57
        return 3;
×
58
    else if(combinedSize <= 512 * 512)
×
59
        return 4;
×
60
    else if(combinedSize <= 1024 * 1024)
×
61
        return 5;
×
62
    else
63
        return 6;
×
64
}
65

66
unsigned GetIslandSize(const MapExtent& size)
4✔
67
{
68
    const unsigned combinedSize = size.x * size.y;
4✔
69
    if(combinedSize <= 64 * 64)
4✔
70
        return 200;
2✔
71
    else if(combinedSize <= 128 * 128)
2✔
72
        return 400;
2✔
73
    else if(combinedSize <= 256 * 256)
×
74
        return 600;
×
75
    else if(combinedSize <= 512 * 512)
×
76
        return 900;
×
77
    else
78
        return 1200;
×
79
}
80

81
unsigned GetSmoothRadius(const MapExtent& size)
6✔
82
{
83
    const unsigned combinedSize = size.x * size.y;
6✔
84
    if(combinedSize <= 128 * 128)
6✔
85
        return 2;
6✔
86
    else if(combinedSize <= 256 * 256)
×
87
        return 3;
×
88
    else if(combinedSize <= 512 * 512)
×
89
        return 4;
×
90
    else if(combinedSize <= 1024 * 1024)
×
91
        return 6;
×
92
    else
93
        return 7;
×
94
}
95

96
unsigned GetSmoothIterations(const MapExtent& size)
6✔
97
{
98
    const unsigned combinedSize = size.x * size.y;
6✔
99
    if(combinedSize <= 64 * 64)
6✔
100
        return 10;
5✔
101
    else if(combinedSize <= 128 * 128)
1✔
102
        return 11;
1✔
103
    else if(combinedSize <= 256 * 256)
×
104
        return 9;
×
105
    else if(combinedSize <= 512 * 512)
×
106
        return 12;
×
107
    else if(combinedSize <= 1024 * 1024)
×
108
        return 15;
×
109
    else
110
        return 13;
×
111
}
112

113
void SmoothHeightMap(NodeMapBase<uint8_t>& z, const ValueRange<uint8_t>& range)
6✔
114
{
115
    int radius = GetSmoothRadius(z.GetSize());
6✔
116
    int iterations = GetSmoothIterations(z.GetSize());
6✔
117

118
    Smooth(iterations, radius, z);
6✔
119
    Scale(z, range.minimum, range.maximum);
6✔
120
}
6✔
121

122
RandomMap::RandomMap(RandomUtility& rnd, Map& map)
6✔
123
    : rnd_(rnd), map_(map), texturizer_(map.z, map.getTextures(), map.textureMap)
6✔
124
{}
6✔
125

126
void RandomMap::Create(const MapSettings& settings)
6✔
127
{
128
    auto defaultHeight = map_.height.minimum + map_.height.GetDifference() / 2;
6✔
129

130
    settings_ = settings;
6✔
131
    map_.z.Resize(settings.size, defaultHeight);
6✔
132

133
    switch(settings.style)
6✔
134
    {
135
        case MapStyle::Water: CreateWaterMap(); break;
1✔
136

137
        case MapStyle::Mixed: CreateMixedMap(); break;
2✔
138

139
        case MapStyle::Land: CreateLandMap(); break;
3✔
140
    }
141

142
    AddObjects(map_, rnd_, settings_);
6✔
143
    AddResources(map_, rnd_, settings_);
6✔
144
    AddAnimals(map_, rnd_);
6✔
145
}
6✔
146

147
std::vector<River> RandomMap::CreateRivers(const MapPoint source)
6✔
148
{
149
    std::vector<River> rivers;
6✔
150

151
    const MapExtent size = settings_.size;
6✔
152
    const unsigned length = size.x + size.y;
6✔
153

154
    for(const auto dir : helpers::EnumRange<Direction>())
96✔
155
    {
156
        if(rnd_.ByChance(settings_.rivers))
36✔
157
        {
158
            const unsigned splitRate = rnd_.RandomValue(0u, 2u);
5✔
159
            rivers.push_back(
5✔
160
              CreateStream(rnd_, map_, source.isValid() ? source : rnd_.Point(map_.size), dir, length, splitRate));
10✔
161
        }
162
    }
163
    return rivers;
12✔
164
}
165

166
void RandomMap::CreateFreeIslands(unsigned waterNodes)
3✔
167
{
168
    const auto islandRadius = GetIslandRadius(map_.size);
3✔
169
    const auto islandAmount = static_cast<double>(settings_.islands) / 100;
3✔
170
    const auto maxIslandSize = GetIslandSize(map_.size);
3✔
171
    const auto minIslandSize = std::min(200u, maxIslandSize);
3✔
172
    auto islandNodes = static_cast<unsigned>(islandAmount * waterNodes);
3✔
173
    auto islandSize = rnd_.RandomValue(minIslandSize, maxIslandSize);
3✔
174
    while(islandNodes >= islandSize)
3✔
175
    {
176
        islandNodes -= islandSize;
×
177
        CreateIsland(map_, rnd_, islandSize, islandRadius, .2);
×
178
        islandSize = rnd_.RandomValue(minIslandSize, maxIslandSize);
×
179
    }
180
}
3✔
181

182
void RandomMap::CreateMixedMap()
2✔
183
{
184
    const auto center = rnd_.Point(map_.size);
2✔
185
    const unsigned maxDistance = map_.z.CalcMaxDistance();
2✔
186

187
    Restructure(map_, [this, &center, maxDistance](const MapPoint& pt) {
2✔
188
        auto weight = 1. - static_cast<float>(map_.z.CalcDistance(pt, center)) / maxDistance;
4,760✔
189
        auto percentage = static_cast<unsigned>(12 * weight);
4,760✔
190
        return rnd_.ByChance(percentage);
4,760✔
191
    });
192
    SmoothHeightMap(map_.z, map_.height);
2✔
193

194
    const double sea = 0.5;
2✔
195
    const double mountain = 0.1;
2✔
196
    const double land = 1. - sea - mountain;
2✔
197

198
    ResetSeaLevel(map_, rnd_, LimitFor(map_.z, sea, map_.height.minimum));
2✔
199

200
    const auto mountainLevel = LimitFor(map_.z, land, static_cast<uint8_t>(map_.height.minimum + 1)) + 1;
2✔
201
    const auto rivers = CreateRivers(center);
4✔
202
    const unsigned waterNodes = helpers::count(map_.z, map_.height.minimum);
2✔
203

204
    CreateFreeIslands(waterNodes);
2✔
205

206
    texturizer_.AddTextures(mountainLevel, GetCoastline(map_.size));
2✔
207

208
    PlaceHarbors(map_, rivers);
2✔
209
    PlaceHeadquarters(map_, rnd_, map_.players, settings_.mountainDistance);
2✔
210
}
2✔
211

212
void RandomMap::CreateWaterMap()
1✔
213
{
214
    const auto center = rnd_.Point(map_.size);
1✔
215
    const unsigned maxDistance = map_.z.CalcMaxDistance();
1✔
216

217
    Restructure(map_, [this, &center, maxDistance](const MapPoint& pt) {
1✔
218
        const auto weight = 1. - static_cast<float>(map_.z.CalcDistance(pt, center)) / maxDistance;
7,052✔
219
        const auto percentage = static_cast<unsigned>(15 * weight * weight);
7,052✔
220
        return rnd_.ByChance(percentage);
7,052✔
221
    });
222
    SmoothHeightMap(map_.z, map_.height);
1✔
223

224
    const double sea = 0.80;      // 20% of map is center island (100% - 80% water)
1✔
225
    const double mountain = 0.05; // 20% of center island is mountain (5% of 20% land)
1✔
226
    const auto seaLevel = LimitFor(map_.z, sea, map_.height.minimum);
1✔
227

228
    ResetSeaLevel(map_, rnd_, seaLevel);
1✔
229

230
    const unsigned waterNodes = helpers::count(map_.z, map_.height.minimum);
1✔
231
    const auto land = 1. - static_cast<double>(waterNodes) / (map_.size.x * map_.size.y) - mountain;
1✔
232
    const auto mountainLevel = LimitFor(map_.z, land, static_cast<uint8_t>(1)) + 1;
1✔
233
    const auto islandSize = GetIslandSize(map_.size);
1✔
234
    const auto islandRadius = GetIslandRadius(map_.size);
1✔
235

236
    std::vector<Island> islands(map_.players);
2✔
237

238
    for(unsigned i = 0; i < map_.players; i++)
3✔
239
    {
240
        islands[i] = CreateIsland(map_, rnd_, islandSize, islandRadius, .2);
2✔
241
    }
242

243
    if(waterNodes > map_.players * islandSize)
1✔
244
    {
245
        CreateFreeIslands(waterNodes - map_.players * islandSize);
1✔
246
    }
247

248
    const auto rivers = CreateRivers(center);
2✔
249

250
    texturizer_.AddTextures(mountainLevel, GetCoastline(map_.size));
1✔
251

252
    PlaceHarbors(map_, rivers);
1✔
253

254
    for(unsigned i = 0; i < map_.players; i++)
3✔
255
    {
256
        PlaceHeadquarter(map_, islands[i], settings_.mountainDistance);
2✔
257
    }
258
}
1✔
259

260
void RandomMap::CreateLandMap()
3✔
261
{
262
    Restructure(map_, [this](auto&&) { return rnd_.ByChance(5); });
7,707✔
263
    SmoothHeightMap(map_.z, map_.height);
3✔
264

265
    const double sea = rnd_.RandomDouble(0.1, 0.2);
3✔
266
    const double mountain = rnd_.RandomDouble(0.15, 0.4 - sea);
3✔
267
    const double land = 1. - sea - mountain;
3✔
268

269
    ResetSeaLevel(map_, rnd_, LimitFor(map_.z, sea, map_.height.minimum));
3✔
270

271
    const auto mountainLevel = LimitFor(map_.z, land, static_cast<uint8_t>(1)) + 1;
3✔
272
    CreateRivers();
3✔
273

274
    texturizer_.AddTextures(mountainLevel, GetCoastline(map_.size));
3✔
275

276
    PlaceHeadquarters(map_, rnd_, map_.players, settings_.mountainDistance);
3✔
277
}
3✔
278

279
Map GenerateRandomMap(RandomUtility& rnd, const WorldDescription& worldDesc, const MapSettings& settings)
6✔
280
{
281
    auto height = GetMaximumHeight(settings.size);
6✔
282
    Map map(settings.size, settings.numPlayers, worldDesc, settings.type, height);
6✔
283
    RandomMap randomMap(rnd, map);
12✔
284
    randomMap.Create(settings);
6✔
285
    return map;
12✔
286
}
287

288
void CreateRandomMap(const boost::filesystem::path& filePath, const MapSettings& settings)
1✔
289
{
290
    RandomUtility rnd;
1✔
291
    WorldDescription worldDesc;
2✔
292
    loadGameData(worldDesc);
1✔
293

294
    Map map = GenerateRandomMap(rnd, worldDesc, settings);
1✔
295
    libsiedler2::Write(filePath, map.CreateArchiv());
1✔
296
}
1✔
297

298
} // namespace rttr::mapGenerator
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc