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

Return-To-The-Roots / s25client / 5724331806

pending completion
5724331806

push

github

web-flow
Merge pull request #1606 from falbrechtskirchinger/pin-windows

Allow excluding windows from being closed via Escape key

62 of 62 new or added lines in 5 files covered. (100.0%)

21755 of 43109 relevant lines covered (50.47%)

32677.6 hits per line

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

78.8
/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 { namespace 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;
3✔
26
        else if(combinedSize <= 128 * 128)
3✔
27
            return 64;
3✔
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;
×
71
        else if(combinedSize <= 128 * 128)
4✔
72
            return 400;
4✔
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;
3✔
101
        else if(combinedSize <= 128 * 128)
3✔
102
            return 11;
3✔
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);
4✔
159
                rivers.push_back(
4✔
160
                  CreateStream(rnd_, map_, source.isValid() ? source : rnd_.Point(map_.size), dir, length, splitRate));
8✔
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)
5✔
175
        {
176
            islandNodes -= islandSize;
2✔
177
            CreateIsland(map_, rnd_, islandSize, islandRadius, .2);
2✔
178
            islandSize = rnd_.RandomValue(minIslandSize, maxIslandSize);
2✔
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;
9,796✔
189
            auto percentage = static_cast<unsigned>(12 * weight);
9,796✔
190
            return rnd_.ByChance(percentage);
9,796✔
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++)
4✔
239
        {
240
            islands[i] = CreateIsland(map_, rnd_, islandSize, islandRadius, .2);
3✔
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++)
4✔
255
        {
256
            PlaceHeadquarter(map_, islands[i], settings_.mountainDistance);
3✔
257
        }
258
    }
1✔
259

260
    void RandomMap::CreateLandMap()
3✔
261
    {
262
        Restructure(map_, [this](auto&&) { return rnd_.ByChance(5); });
9,075✔
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