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

ParadoxGameConverters / Vic3ToHoI4 / 16384372731

19 Jul 2025 03:18AM UTC coverage: 94.208% (+0.02%) from 94.185%
16384372731

push

github

web-flow
Fix military conversion. (#740)

* Import and use combat units

* Ignore unregistered items

* Clean up cmake changes

* More cmake cleanup

* Add tests for combat unit importer

* Fix linux build

* Fix naming.

* Add tests for combat units importer

* Add another test for unit mapper

147 of 163 new or added lines in 7 files covered. (90.18%)

4 existing lines in 1 file now uncovered.

22155 of 23517 relevant lines covered (94.21%)

56339.28 hits per line

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

78.78
/src/vic3_world/world/vic3_world_importer.cpp
1
#include "src/vic3_world/world/vic3_world_importer.h"
2

3
#include <external/commonItems/Color.h>
4
#include <external/commonItems/CommonRegexes.h>
5
#include <external/commonItems/Date.h>
6
#include <external/commonItems/Log.h>
7
#include <external/commonItems/ModLoader/Mod.h>
8
#include <external/commonItems/ModLoader/ModLoader.h>
9
#include <external/commonItems/Parser.h>
10
#include <external/commonItems/ParserHelpers.h>
11
#include <external/fmt/include/fmt/format.h>
12
#include <external/rakaly/rakaly.h>
13

14
#include <filesystem>
15
#include <fstream>
16
#include <numeric>
17
#include <ranges>
18
#include <sstream>
19
#include <string>
20

21
#include "src/support/date_fmt.h"
22
#include "src/support/progress_manager.h"
23
#include "src/vic3_world/buildings/buildings_importer.h"
24
#include "src/vic3_world/characters/vic3_character_manager.h"
25
#include "src/vic3_world/countries/country_definitions_importer.h"
26
#include "src/vic3_world/countries/vic3_countries_importer.h"
27
#include "src/vic3_world/countries/vic3_country.h"
28
#include "src/vic3_world/country_rankings/country_rankings.h"
29
#include "src/vic3_world/country_rankings/country_rankings_importer.h"
30
#include "src/vic3_world/cultures/culture_definitions_importer.h"
31
#include "src/vic3_world/cultures/cultures_importer.h"
32
#include "src/vic3_world/elections/elections_importer.h"
33
#include "src/vic3_world/ideologies/ideologies_importer.h"
34
#include "src/vic3_world/institutions/institutions_importer.h"
35
#include "src/vic3_world/interest_groups/interest_groups_importer.h"
36
#include "src/vic3_world/laws/laws_importer.h"
37
#include "src/vic3_world/military/combat_unit.h"
38
#include "src/vic3_world/military/combat_units_importer.h"
39
#include "src/vic3_world/military/military_formations_importer.h"
40
#include "src/vic3_world/pacts/pacts_importer.h"
41
#include "src/vic3_world/provinces/vic3_province_definitions.h"
42
#include "src/vic3_world/provinces/vic3_province_definitions_loader.h"
43
#include "src/vic3_world/states/state_regions_importer.h"
44
#include "src/vic3_world/states/vic3_state.h"
45
#include "src/vic3_world/states/vic3_states_importer.h"
46
#include "src/vic3_world/technology/vic3_technology_importer.h"
47
#include "src/vic3_world/wars/wars_importer.h"
48

49

50

51
using std::filesystem::path;
52

53

54

55
namespace
56
{
57

58
std::string ReadSave(const path& save_filename)
7✔
59
{
60
   Log(LogLevel::Info) << "  -> Opening save";
7✔
61
   std::ifstream save_file(save_filename, std::ios::in | std::ios::binary);
7✔
62
   Log(LogLevel::Info) << "  -> Getting save size";
7✔
63
   const auto save_size = static_cast<std::basic_string<char>::size_type>(file_size(save_filename));
7✔
64
   Log(LogLevel::Info) << "  -> Getting string text";
6✔
65
   std::string save_string(save_size, '\0');
6✔
66
   save_file.read(save_string.data(), save_size);
6✔
67

68
   return save_string;
12✔
69
}
7✔
70

71

72
std::istringstream GetSaveMeta(const rakaly::GameFile& save, const std::string& save_string)
6✔
73
{
74
   Log(LogLevel::Info) << "  -> Getting save meta";
6✔
75
   std::string save_meta;
6✔
76

77
   if (save.is_binary())
6✔
78
   {
79
      Log(LogLevel::Info) << "    -> Save was binary, melting meta";
×
80
      const auto melt = save.meltMeta();
×
81
      if (!melt || melt->has_unknown_tokens())
×
82
      {
83
         throw std::runtime_error("Unable to melt ironman save's metadata");
×
84
      }
85

86
      Log(LogLevel::Info) << "    -> writing melted meta";
×
87
      melt->writeData(save_meta);
×
88
   }
×
89
   else
90
   {
91
      Log(LogLevel::Info) << "    -> writing meta";
6✔
92
      save_meta = save_string;
6✔
93
   }
94

95
   return std::istringstream{save_meta};
12✔
96
}
6✔
97

98

99
std::vector<Mod> GetModsFromSave(const std::vector<std::string>& mod_names)
6✔
100
{
101
   std::vector<Mod> mods;
6✔
102
   for (const auto& mod_name: mod_names)
16✔
103
   {
104
      Mod mod(mod_name, "");
10✔
105
      mods.push_back(mod);
10✔
106
   }
10✔
107

108
   return mods;
6✔
109
}
×
110

111

112
std::istringstream MeltSave(const rakaly::GameFile& save, const std::string& save_string)
6✔
113
{
114
   const auto melt = save.melt();
6✔
115
   if (melt.has_unknown_tokens())
6✔
116
   {
117
      Log(LogLevel::Warning) << "Save had unmeltable tokens.";
×
118
   }
119

120
   std::string melted_save_string;
6✔
121
   melt.writeData(melted_save_string);
6✔
122

123
   if (melted_save_string.empty())
6✔
124
   {
125
      return std::istringstream{save_string};
6✔
126
   }
127
   return std::istringstream{melted_save_string};
×
128
}
6✔
129

130

131
void AssignCulturesToCountries(std::map<int, vic3::Country>& countries, const std::map<int, std::string>& cultures)
6✔
132
{
133
   for (auto& [country_id, country]: countries)
16✔
134
   {
135
      for (const auto& id: country.GetPrimaryCultureIds())
20✔
136
      {
137
         if (const auto culture_itr = cultures.find(id); culture_itr != cultures.end())
10✔
138
         {
139
            country.AddPrimaryCulture(culture_itr->second);
10✔
140
         }
141
         else
142
         {
143
            Log(LogLevel::Warning) << fmt::format("Country: {} could not find a match for Culture: {}.",
×
144
                country_id,
145
                id);
×
146
         }
147
      }
148
   }
149
}
6✔
150

151
void AssignCulturesToCharacters(std::map<int, vic3::Character>& characters, const std::map<int, std::string>& cultures)
6✔
152
{
153
   for (auto& character: characters | std::ranges::views::values)
31✔
154
   {
155
      if (const auto culture_itr = cultures.find(character.GetCultureId()); culture_itr != cultures.end())
25✔
156
      {
157
         character.SetCulture(culture_itr->second);
25✔
158
      }
159
      else
160
      {
161
         Log(LogLevel::Warning) << fmt::format("Character {} {} could not find a match for Culture: {}.",
×
162
             character.GetFirstName(),
×
163
             character.GetLastName(),
×
164
             character.GetCultureId());
×
165
      }
166
   }
167
}
6✔
168

169

170
void AssignOwnersToStates(const std::map<int, vic3::Country>& countries, std::map<int, vic3::State>& states)
6✔
171
{
172
   for (auto& [state_number, state]: states)
21✔
173
   {
174
      const auto& possible_owner_number = state.GetOwnerNumber();
15✔
175
      if (!possible_owner_number.has_value())
15✔
176
      {
177
         continue;
5✔
178
      }
179

180
      if (const auto country_itr = countries.find(*possible_owner_number); country_itr != countries.end())
10✔
181
      {
182
         state.SetOwnerTag(country_itr->second.GetTag());
5✔
183
      }
184
      else
185
      {
186
         Log(LogLevel::Warning) << fmt::format("State {} had an owner with no definition.", state_number);
5✔
187
      }
188
   }
189
}
6✔
190

191
void AssignIgsToCountries(std::map<int, vic3::Country>& countries, const std::map<int, vic3::InterestGroup>& igs)
6✔
192
{
193
   for (const auto& [ig_id, ig]: igs)
21✔
194
   {
195
      if (const auto country_itr = countries.find(ig.GetCountryId()); country_itr != countries.end())
15✔
196
      {
197
         country_itr->second.AddInterestGroupId(ig_id);
15✔
198
      }
199
      else
200
      {
201
         Log(LogLevel::Warning) << fmt::format("Country: {} not found. Ignoring {} with ID: {}.",
×
202
             ig.GetCountryId(),
×
203
             ig.GetType(),
×
204
             ig_id);
×
205
      }
206
   }
207
}
6✔
208

209

210
void AssignCharactersToCountries(const std::map<int, vic3::Character>& characters,
6✔
211
    const std::map<int, std::vector<int>>& country_character_map,
212
    std::map<int, vic3::Country>& countries)
213
{
214
   for (const auto& [country_id, character_ids]: country_character_map)
16✔
215
   {
216
      if (const auto country_itr = countries.find(country_id); country_itr != countries.end())
10✔
217
      {
218
         std::vector<int> important_character_ids;
10✔
219
         std::ranges::copy_if(character_ids, std::back_inserter(important_character_ids), [characters](const int id) {
10✔
220
            if (const auto& character_itr = characters.find(id); character_itr != characters.end())
20✔
221
            {
222
               const auto& roles = character_itr->second.GetRoles();
20✔
223
               if (roles.size() > 1 || (!roles.contains("general") && !roles.contains("admiral")))
20✔
224
               {
225
                  return true;
20✔
226
               }
227
               return character_itr->second.IsCommander();  // Only employed officers please
5✔
228
            }
229
            return false;
×
230
         });
231
         country_itr->second.SetCharacterIds(important_character_ids);
10✔
232
      }
10✔
233
      else
234
      {
235
         Log(LogLevel::Warning) << fmt::format("Country: {} not found. can't place character ids", country_id);
×
236
      }
237
   }
238
}
16✔
239

240

241
void AssignMilitaryFormationsToCountries(const std::map<int, vic3::MilitaryFormation>& military_formations,
6✔
242
    const std::vector<vic3::CombatUnit>& combat_units,
243
    std::map<int, vic3::Country>& countries)
244
{
245
   std::map<int, std::map<int, vic3::MilitaryFormation>> army_formations_by_country;
6✔
246
   std::map<int, std::map<int, vic3::MilitaryFormation>> navy_formations_by_country;
6✔
247
   for (const auto& [formation_number, formation]: military_formations)
16✔
248
   {
249
      if (formation.type == vic3::MilitaryFormationType::kArmy)
10✔
250
      {
251
         auto [iterator, success] = army_formations_by_country.emplace(formation.country,
10✔
252
             std::map<int, vic3::MilitaryFormation>{{formation_number, formation}});
15✔
253
         if (!success)
5✔
254
         {
255
            iterator->second.emplace(formation_number, formation);
×
256
         }
257
      }
258
      else
259
      {
260
         auto [iterator, success] = navy_formations_by_country.emplace(formation.country,
10✔
261
             std::map<int, vic3::MilitaryFormation>{{formation_number, formation}});
15✔
262
         if (!success)
5✔
263
         {
264
            iterator->second.emplace(formation_number, formation);
×
265
         }
266
      }
267
   }
268

269
   for (const vic3::CombatUnit& combat_unit: combat_units)
6✔
270
   {
NEW
271
      if (!combat_unit.country)
×
272
      {
NEW
273
         continue;
×
274
      }
NEW
275
      auto country_itr = army_formations_by_country.find(combat_unit.country.value());
×
NEW
276
      if (country_itr == army_formations_by_country.end())
×
277
      {
NEW
278
         continue;
×
279
      }
280

NEW
281
      if (!combat_unit.formation)
×
282
      {
NEW
283
         continue;
×
284
      }
NEW
285
      auto formation_itr = country_itr->second.find(combat_unit.formation.value());
×
NEW
286
      if (formation_itr == country_itr->second.end())
×
287
      {
NEW
288
         continue;
×
289
      }
290

NEW
291
      formation_itr->second.combat_units.push_back(combat_unit);
×
292
   }
293

294
   for (const auto& [country_number, army_formations]: army_formations_by_country)
11✔
295
   {
296
      auto country = countries.find(country_number);
5✔
297
      if (country == countries.end())
5✔
298
      {
299
         Log(LogLevel::Warning) << fmt::format("Could not find country {} to assign army formations.", country_number);
×
300
         continue;
×
301
      }
302
      country->second.SetArmyFormations(army_formations);
5✔
303
   }
304
   for (const auto& [country_number, navy_formations]: navy_formations_by_country)
11✔
305
   {
306
      auto country = countries.find(country_number);
5✔
307
      if (country == countries.end())
5✔
308
      {
309
         Log(LogLevel::Warning) << fmt::format("Could not find country {} to assign navy formations.", country_number);
×
310
         continue;
×
311
      }
312
      country->second.SetNavyFormations(navy_formations);
5✔
313
   }
314
}
16✔
315

316

317
void ApplySubjectRelationships(const std::map<int, vic3::Pact>& pacts, std::map<int, vic3::Country>& countries)
6✔
318
{
319
   for (const vic3::Pact& pact: pacts | std::views::values)
16✔
320
   {
321
      if (pact.IsSubjectRelationship())
10✔
322
      {
323
         auto overlord = countries.find(pact.GetFirstId());
5✔
324
         auto subject = countries.find(pact.GetSecondId());
5✔
325
         if (overlord != countries.end() && subject != countries.end())
5✔
326
         {
327
            overlord->second.AddPuppet(pact.GetSecondId());
5✔
328
            subject->second.AddOverlord(pact.GetFirstId());
5✔
329
            if (subject->second.GetColor() == commonItems::Color{})
5✔
330
            {
331
               subject->second.SetColor(overlord->second.GetColor());
×
332
            }
333
         }
334
      }
335
   }
336
}
6✔
337

338

339
std::map<std::string, int> MapCountryTagsToId(std::map<int, vic3::Country>& countries)
6✔
340
{
341
   std::map<std::string, int> tag_to_id_map;
6✔
342
   for (const auto& [id, country]: countries)
16✔
343
   {
344
      tag_to_id_map.emplace(country.GetTag(), id);
10✔
345
   }
346
   return tag_to_id_map;
6✔
347
}
×
348

349
void AssignHomeCountriesToExiledAgitators(const std::map<std::string, int>& tag_to_id_map,
6✔
350
    std::map<int, vic3::Character>& characters)
351
{
352
   for (auto& character: characters | std::views::values)
31✔
353
   {
354
      if (character.GetOriginTag().empty())
25✔
355
      {
356
         continue;
15✔
357
      }
358

359
      if (const auto& id_itr = tag_to_id_map.find(character.GetOriginTag()); id_itr != tag_to_id_map.end())
10✔
360
      {
361
         character.SetOriginCountryId(id_itr->second);
10✔
362
      }
363
   }
364
}
6✔
365

366
int MungePlaythroughIdIntoInteger(const std::string& playthrough_id_string)
5✔
367
{
368
   return std::accumulate(playthrough_id_string.begin(), playthrough_id_string.end(), 0, [](int id, const char& digit) {
5✔
369
      return id + static_cast<int>(digit);
180✔
370
   });
5✔
371
}
372

373
}  // namespace
374

375

376
vic3::World vic3::ImportWorld(const configuration::Configuration& configuration,
7✔
377
    const commonItems::ConverterVersion& converter_version)
378
{
379
   WorldOptions world_options;
7✔
380
   Log(LogLevel::Info) << "*** Hello Vic3, loading World. ***";
7✔
381
   std::string save_string = ReadSave(configuration.save_game);
7✔
382
   Log(LogLevel::Info) << "  -> Parsing save";
6✔
383
   const rakaly::GameFile save = rakaly::parseVic3(save_string);
6✔
384

385
   std::istringstream meta_stream = GetSaveMeta(save, save_string);
6✔
386

387
   Log(LogLevel::Info) << "-> Reading Vic3 save metadata.";
6✔
388
   std::vector<std::string> mod_names;
6✔
389

390
   commonItems::parser meta_parser;
6✔
391
   meta_parser.registerKeyword("game_date", [&mod_names](std::istream& input_stream) {
6✔
392
      date game_date(commonItems::getString(input_stream));
5✔
393
      Log(LogLevel::Info) << fmt::format("Converting at {}.", game_date);
5✔
394
   });
5✔
395
   meta_parser.registerKeyword("mods", [&mod_names](std::istream& input_stream) {
6✔
396
      mod_names = commonItems::stringList(input_stream).getStrings();
5✔
397
   });
5✔
398
   meta_parser.registerKeyword("version", [&converter_version](std::istream& input_stream) {
6✔
399
      const auto str_version = commonItems::getString(input_stream);
×
400
      GameVersion version = GameVersion(str_version);
×
401
      Log(LogLevel::Info) << "Savegame version: " << version;
×
402

403
      if (converter_version.getMinSource() > version)
×
404
      {
405
         Log(LogLevel::Error) << "Converter requires a minimum save from v"
×
406
                              << converter_version.getMinSource().toShortString();
×
407
         throw std::runtime_error("Savegame vs converter version mismatch!");
×
408
      }
409
      if (!converter_version.getMaxSource().isLargerishThan(version))
×
410
      {
411
         Log(LogLevel::Error) << "Converter requires a maximum save from v"
×
412
                              << converter_version.getMaxSource().toShortString();
×
413
         throw std::runtime_error("Savegame vs converter version mismatch!");
×
414
      }
415
   });
×
416
   meta_parser.IgnoreUnregisteredItems();
6✔
417
   meta_parser.parseStream(meta_stream);
6✔
418

419
   Log(LogLevel::Info) << "-> Loading Vic3 mods.";
6✔
420
   commonItems::ModLoader mod_loader;
6✔
421
   mod_loader.loadMods(std::vector<path>{configuration.vic3_mod_path, configuration.vic3_steam_mod_path},
18✔
422
       GetModsFromSave(mod_names));
12✔
423

424
   Log(LogLevel::Info) << "-> Reading Vic3 install.";
6✔
425
   commonItems::ModFilesystem mod_filesystem(configuration.vic3_directory / "game", mod_loader.getMods());
6✔
426
   Log(LogLevel::Info) << "->   Importing state regions.";
6✔
427
   StateRegions state_regions = ImportStateRegions(mod_filesystem);
6✔
428
   Log(LogLevel::Info) << "->   Loading province definitions.";
6✔
429
   world_options.province_definitions = LoadProvinceDefinitions(state_regions, mod_filesystem);
6✔
430
   world_options.state_regions = state_regions.name_to_region_map;
6✔
431
   Log(LogLevel::Info) << "->   Scraping localizations";
6✔
432
   commonItems::LocalizationDatabase localizations("english",
433
       {"braz_por",
434
           "french",
435
           "german",
436
           "japanese",
437
           "korean",
438
           "polish",
439
           "russian",
440
           "simp_chinese",
441
           "spanish",
442
           "turkish"});
66✔
443
   localizations.ScrapeLocalizations(mod_filesystem, "localization");
6✔
444
   world_options.localizations = localizations;
6✔
445
   world_options.culture_definitions = ImportCultureDefinitions(mod_filesystem);
6✔
446
   ProgressManager::AddProgress(5);
6✔
447

448
   Log(LogLevel::Info) << "-> Reading Vic3 save.";
6✔
449
   std::istringstream save_stream = MeltSave(save, save_string);
6✔
450
   ProgressManager::AddProgress(1);
6✔
451
   Log(LogLevel::Info) << "-> Processing Vic3 save.";
6✔
452
   const std::map<std::string, commonItems::Color> color_definitions = ImportCountryColorDefinitions(mod_filesystem);
6✔
453
   std::map<int, std::string> cultures;
6✔
454
   std::map<int, std::vector<int>> country_character_map;
6✔
455
   std::map<int, MilitaryFormation> military_formations;
6✔
456
   std::vector<CombatUnit> combat_units;
6✔
457

458
   commonItems::parser save_parser;
6✔
459
   save_parser.registerKeyword("playthrough_id", [&world_options](std::istream& input_stream) {
6✔
460
      world_options.playthrough_id = MungePlaythroughIdIntoInteger(commonItems::getString(input_stream));
5✔
461
   });
5✔
462
   save_parser.registerKeyword("country_manager", [&world_options, color_definitions](std::istream& input_stream) {
6✔
463
      world_options.countries = ImportCountries(color_definitions, input_stream);
5✔
464
   });
5✔
465
   save_parser.registerKeyword("states", [&world_options](std::istream& input_stream) {
6✔
466
      world_options.states = ImportStates(input_stream);
5✔
467
   });
5✔
468
   save_parser.registerKeyword("technology", [&world_options](std::istream& input_stream) {
6✔
469
      world_options.acquired_technologies = ImportAcquiredTechnologies(input_stream);
5✔
470
   });
5✔
471
   save_parser.registerKeyword("country_rankings", [&world_options](std::istream& input_stream) {
6✔
472
      world_options.country_rankings = ImportCountryRankings(input_stream);
5✔
473
   });
5✔
474
   save_parser.registerKeyword("laws", [&world_options](std::istream& input_stream) {
6✔
475
      for (const auto& [country_number, active_laws]: ImportLaws(input_stream))
10✔
476
      {
477
         auto country_itr = world_options.countries.find(country_number);
5✔
478
         if (country_itr == world_options.countries.end())
5✔
479
         {
480
            continue;
×
481
         }
482
         country_itr->second.SetActiveLaws(active_laws);
5✔
483
      }
5✔
484
   });
5✔
485

486
   save_parser.registerKeyword("institutions", InstitutionsImporter(world_options.institutions));
6✔
487
   save_parser.registerKeyword("cultures", [&cultures](std::istream& input_stream) {
6✔
488
      cultures = ImportCultures(input_stream);
5✔
489
   });
5✔
490
   save_parser.registerKeyword("character_manager",
6✔
491
       [&world_options, &country_character_map](std::istream& input_stream) {
6✔
492
          const CharacterManager character_manager(input_stream);
5✔
493
          world_options.characters = character_manager.GetCharacters();
5✔
494
          country_character_map = character_manager.GetCountryCharacterMap();
5✔
495
       });
5✔
496
   save_parser.registerKeyword("interest_groups", [&world_options](std::istream& input_stream) {
6✔
497
      world_options.igs = ImportInterestGroups(input_stream);
5✔
498
   });
5✔
499
   save_parser.registerKeyword("building_manager", [&world_options](std::istream& input_stream) {
6✔
500
      world_options.buildings = ImportBuildings(input_stream);
5✔
501
   });
5✔
502
   save_parser.registerKeyword("military_formation_manager", [&military_formations](std::istream& input_stream) {
6✔
503
      military_formations = ImportMilitaryFormations(input_stream);
5✔
504
   });
5✔
505
   save_parser.registerKeyword("new_combat_unit_manager", [&combat_units](std::istream& input_stream) {
6✔
NEW
506
      combat_units = ImportCombatUnits(input_stream);
×
NEW
507
   });
×
508
   save_parser.registerKeyword("election_manager", [&world_options](std::istream& input_stream) {
6✔
509
      for (const auto& [country_number, last_election]: ImportElections(input_stream))
×
510
      {
511
         auto country_itr = world_options.countries.find(country_number);
×
512
         if (country_itr == world_options.countries.end())
×
513
         {
514
            continue;
×
515
         }
516
         country_itr->second.SetLastElection(last_election);
×
517
      }
×
518
   });
×
519
   save_parser.registerKeyword("pacts", [&world_options](std::istream& input_stream) {
6✔
520
      world_options.pacts = ImportPacts(input_stream);
5✔
521
   });
5✔
522
   save_parser.registerKeyword("diplomatic_plays", [&world_options](std::istream& input_stream) {
6✔
523
      world_options.wars = ImportWars(input_stream);
×
524
   });
×
525
   save_parser.registerRegex("SAV.*",
6✔
526
       []([[maybe_unused]] const std::string& unused, [[maybe_unused]] std::istream& input_stream) {
×
527
       });
6✔
528
   save_parser.IgnoreUnregisteredItems();
6✔
529

530
   save_parser.parseStream(save_stream);
6✔
531
   Log(LogLevel::Info) << fmt::format("\t{} countries imported", world_options.countries.size());
6✔
532
   Log(LogLevel::Info) << fmt::format("\t{} states imported", world_options.states.size());
6✔
533
   Log(LogLevel::Info) << fmt::format("\t{} countries acquired technologies",
12✔
534
       world_options.acquired_technologies.size());
12✔
535
   Log(LogLevel::Info) << fmt::format("\t{} in goods being sold",
12✔
536
       world_options.buildings.GetTotalGoodSalesValueInWorld());
12✔
537
   ProgressManager::AddProgress(10);
6✔
538

539
   AssignCulturesToCountries(world_options.countries, cultures);
6✔
540
   ProgressManager::AddProgress(1);
6✔
541
   AssignCulturesToCharacters(world_options.characters, cultures);
6✔
542
   ProgressManager::AddProgress(1);
6✔
543
   AssignOwnersToStates(world_options.countries, world_options.states);
6✔
544
   ProgressManager::AddProgress(1);
6✔
545
   const auto& country_tag_to_id_map = MapCountryTagsToId(world_options.countries);
6✔
546
   AssignHomeCountriesToExiledAgitators(country_tag_to_id_map, world_options.characters);
6✔
547
   ProgressManager::AddProgress(1);
6✔
548
   AssignIgsToCountries(world_options.countries, world_options.igs);
6✔
549
   ProgressManager::AddProgress(1);
6✔
550
   AssignCharactersToCountries(world_options.characters, country_character_map, world_options.countries);
6✔
551
   ProgressManager::AddProgress(1);
6✔
552
   AssignMilitaryFormationsToCountries(military_formations, combat_units, world_options.countries);
6✔
553
   ProgressManager::AddProgress(1);
6✔
554
   ApplySubjectRelationships(world_options.pacts, world_options.countries);
6✔
555
   ProgressManager::AddProgress(1);
6✔
556
   vic3::IdeologiesImporter ideologies_importer;
6✔
557
   world_options.ideologies = ideologies_importer.ImportIdeologies(mod_filesystem);
6✔
558
   ProgressManager::AddProgress(1);
6✔
559
   return World(world_options);
12✔
560
}
31✔
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

© 2025 Coveralls, Inc