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

ParadoxGameConverters / Vic3ToHoI4 / 16851853331

09 Aug 2025 05:21PM UTC coverage: 94.214% (+0.01%) from 94.201%
16851853331

Pull #746

github

web-flow
Merge 902d0a8c6 into 27b1ac9ea
Pull Request #746: More triggers

374 of 431 new or added lines in 32 files covered. (86.77%)

1 existing line in 1 file now uncovered.

22488 of 23869 relevant lines covered (94.21%)

56595.73 hits per line

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

85.21
/src/hoi4_world/world/hoi4_world_converter.cpp
1
#include "src/hoi4_world/world/hoi4_world_converter.h"
2

3
#include <external/commonItems/Log.h>
4
#include <external/fmt/include/fmt/format.h>
5

6
#include <ranges>
7

8
#include "hoi4_world.h"
9
#include "src/hoi4_world/characters/hoi4_character.h"
10
#include "src/hoi4_world/characters/hoi4_characters_converter.h"
11
#include "src/hoi4_world/countries/hoi4_countries_converter.h"
12
#include "src/hoi4_world/diplomacy/hoi4_war_converter.h"
13
#include "src/hoi4_world/focus_trees/focus_tree_assembler.h"
14
#include "src/hoi4_world/localizations/localizations_converter.h"
15
#include "src/hoi4_world/map/buildings_creator.h"
16
#include "src/hoi4_world/map/coastal_provinces_creator.h"
17
#include "src/hoi4_world/map/hoi4_province_definition_importer.h"
18
#include "src/hoi4_world/map/railways_converter.h"
19
#include "src/hoi4_world/map/resources_map_importer.h"
20
#include "src/hoi4_world/map/strategic_regions_importer.h"
21
#include "src/hoi4_world/roles/roles_importer.h"
22
#include "src/hoi4_world/roles/stories_creator.h"
23
#include "src/hoi4_world/states/default_states_importer.h"
24
#include "src/hoi4_world/states/hoi4_states_converter.h"
25
#include "src/hoi4_world/world/hoi4_world_framework_builder.h"
26
#include "src/mappers/culture/culture_graphics_mapper_importer.h"
27
#include "src/mappers/technology/tech_mappings_importer.h"
28
#include "src/maps/map_data.h"
29
#include "src/maps/map_data_importer.h"
30
#include "src/support/progress_manager.h"
31
#include "src/vic3_world/wars/war.h"
32

33

34

35
namespace
36
{
37

38
std::map<std::string, vic3::ProvinceType> GatherVic3SignificantProvinces(
14✔
39
    const std::map<std::string, vic3::StateRegion>& vic3_state_regions)
40
{
41
   std::map<std::string, vic3::ProvinceType> vic3_significant_provinces;
14✔
42

43
   for (const vic3::StateRegion& vic3_state_region: vic3_state_regions | std::views::values)
100✔
44
   {
45
      const std::map<vic3::ProvinceId, vic3::ProvinceType>& significant_provinces =
46
          vic3_state_region.GetSignificantProvinces();
86✔
47
      for (const auto& [province, type]: significant_provinces)
186✔
48
      {
49
         vic3_significant_provinces.emplace(province, type);
100✔
50
      }
51
   }
52

53
   return vic3_significant_provinces;
14✔
54
}
×
55

56

57
std::set<std::string> MapPowers(const std::set<int>& source_powers, const mappers::CountryMapper& country_mapper)
28✔
58
{
59
   std::set<std::string> powers;
28✔
60

61
   for (const int great_power_number: source_powers)
44✔
62
   {
63
      if (std::optional<std::string> hoi4_tag = country_mapper.GetHoiTag(great_power_number); hoi4_tag)
16✔
64
      {
65
         powers.insert(*hoi4_tag);
16✔
66
      }
16✔
67
   }
68

69
   return powers;
28✔
70
}
×
71

72

73
std::optional<int> GetCapitalStateNumber(int vic3_country_number,
80✔
74
    const mappers::CountryMapper& country_mapper,
75
    const std::map<std::string, hoi4::Country>& hoi4_countries,
76
    int num_states)
77
{
78
   const std::optional<std::string> possible_tag = country_mapper.GetHoiTag(vic3_country_number);
80✔
79
   if (!possible_tag)
80✔
80
   {
81
      return std::nullopt;
×
82
   }
83
   const auto& country_itr = hoi4_countries.find(*possible_tag);
80✔
84
   if (country_itr == hoi4_countries.end())
80✔
85
   {
86
      return std::nullopt;
×
87
   }
88

89
   const std::optional<int> possible_capital_state_num = country_itr->second.GetCapitalState();
80✔
90
   if (!possible_capital_state_num || num_states < *possible_capital_state_num)
80✔
91
   {
92
      return std::nullopt;
×
93
   }
94

95
   return possible_capital_state_num;
80✔
96
}
80✔
97

98

99
void MarkCapitalsAsCapitals(const std::map<std::string, hoi4::Country>& countries, std::vector<hoi4::State>& states)
14✔
100
{
101
   for (const hoi4::Country& country: countries | std::views::values)
104✔
102
   {
103
      const std::optional<int> possible_capital = country.GetCapitalState();
90✔
104
      if (!possible_capital)
90✔
105
      {
106
         continue;
7✔
107
      }
108
      if (*possible_capital - 1 > states.size())
83✔
109
      {
NEW
110
         continue;
×
111
      }
112

113
      hoi4::State& capital_state = states.at(*possible_capital - 1);
83✔
114
      capital_state.SetIsCapital(true);
83✔
115
   }
116
}
14✔
117

118

119
void IncreaseAirBasesInCapitals(const std::map<std::string, hoi4::Country>& countries, std::vector<hoi4::State>& states)
14✔
120
{
121
   for (const hoi4::Country& country: countries | std::views::values)
104✔
122
   {
123
      const std::optional<int> possible_capital = country.GetCapitalState();
90✔
124
      if (!possible_capital)
90✔
125
      {
126
         continue;
7✔
127
      }
128
      if (*possible_capital - 1 > states.size())
83✔
129
      {
130
         continue;
×
131
      }
132

133
      hoi4::State& capital_state = states.at(*possible_capital - 1);
83✔
134
      capital_state.IncreaseAirBaseLevel(5);
83✔
135
   }
136
}
14✔
137

138

139
void IncreaseVictoryPointsInCapitals(std::vector<hoi4::State>& states,
14✔
140
    const vic3::CountryRankings& country_rankings,
141
    const mappers::CountryMapper& country_mapper,
142
    const std::map<std::string, hoi4::Country>& countries)
143
{
144
   const int num_great_powers = static_cast<int>(country_rankings.GetGreatPowers().size());
14✔
145
   int num_handled_great_powers = 0;
14✔
146
   const int num_major_powers = static_cast<int>(country_rankings.GetMajorPowers().size());
14✔
147
   int num_handled_major_powers = 0;
14✔
148
   int num_handled_others = 0;
14✔
149
   for (int vic3_country_number: country_rankings.GetScoredCountries() | std::views::values)
94✔
150
   {
151
      std::optional<int> possible_capital_state_number =
152
          GetCapitalStateNumber(vic3_country_number, country_mapper, countries, static_cast<int>(states.size()));
80✔
153
      if (!possible_capital_state_number)
80✔
154
      {
155
         continue;
×
156
      }
157
      hoi4::State& capital_state = states[*possible_capital_state_number - 1];
80✔
158

159
      if (country_rankings.GetGreatPowers().contains(vic3_country_number))
80✔
160
      {
161
         if (num_handled_great_powers < num_great_powers / 2)
5✔
162
         {
163
            capital_state.SetHighestVictoryPointValue(50);
2✔
164
         }
165
         else
166
         {
167
            capital_state.SetHighestVictoryPointValue(40);
3✔
168
         }
169
         ++num_handled_great_powers;
5✔
170
      }
171
      else if (country_rankings.GetMajorPowers().contains(vic3_country_number))
75✔
172
      {
173
         if (num_handled_major_powers < num_major_powers / 2)
5✔
174
         {
175
            capital_state.SetHighestVictoryPointValue(30);
2✔
176
         }
177
         else
178
         {
179
            capital_state.SetHighestVictoryPointValue(25);
3✔
180
         }
181
         ++num_handled_major_powers;
5✔
182
      }
183
      else
184
      {
185
         if (num_handled_others < 30)
70✔
186
         {
187
            capital_state.SetHighestVictoryPointValue(20);
30✔
188
         }
189
         else if (num_handled_others < 60)
40✔
190
         {
191
            capital_state.SetHighestVictoryPointValue(15);
30✔
192
         }
193
         else
194
         {
195
            capital_state.SetHighestVictoryPointValue(10);
10✔
196
         }
197
         ++num_handled_others;
70✔
198
      }
199
   }
200
}
14✔
201

202

203
void LogVictoryPointData(const std::vector<hoi4::State>& states)
14✔
204
{
205
   std::map<int, int> victory_point_values;
14✔
206
   for (const hoi4::State& state: states)
108✔
207
   {
208
      for (int victory_point_value: state.GetVictoryPoints() | std::views::values)
183✔
209
      {
210
         const auto& [itr, success] = victory_point_values.emplace(victory_point_value, 1);
89✔
211
         if (!success)
89✔
212
         {
213
            itr->second++;
76✔
214
         }
215
      }
216
   }
217

218
   Log(LogLevel::Info) << "Victory point data:";
14✔
219
   for (const auto& [value, num_instances]: victory_point_values)
27✔
220
   {
221
      Log(LogLevel::Info) << fmt::format("\t{} victory points of value {}", num_instances, value);
13✔
222
   }
223
}
14✔
224

225

226
void ConvertWars(const std::vector<vic3::War>& source_wars,
14✔
227
    const mappers::CountryMapper& country_mapper,
228
    std::map<std::string, hoi4::Country>& countries)
229
{
230
   std::set<std::string> independent_countries;
14✔
231
   std::ranges::copy(countries | std::views::keys, std::inserter(independent_countries, independent_countries.begin()));
14✔
232

233
   for (const vic3::War& source_war: source_wars)
15✔
234
   {
235
      std::optional<hoi4::War> war = hoi4::ConvertWar(source_war, independent_countries, country_mapper);
1✔
236
      if (!war.has_value())
1✔
237
      {
238
         continue;
×
239
      }
240

241
      if (auto country_itr = countries.find(war->original_attacker); country_itr != countries.end())
1✔
242
      {
243
         country_itr->second.AddWar(*war);
1✔
244
      }
245
   }
1✔
246
}
14✔
247

248
}  // namespace
249

250
hoi4::World hoi4::ConvertWorld(const commonItems::ModFilesystem& hoi4_mod_filesystem,
14✔
251
    const vic3::World& source_world,
252
    const mappers::WorldMapper& world_mapper,
253
    std::future<hoi4::WorldFramework> world_framework_future,
254
    const configuration::Configuration& config)
255
{
256
   Log(LogLevel::Info) << "Creating Hoi4 world";
14✔
257

258
   std::map<std::string, vic3::ProvinceType> vic3_significant_provinces =
259
       GatherVic3SignificantProvinces(source_world.GetStateRegions());
14✔
260
   hoi4::WorldFramework world_framework = world_framework_future.get();
14✔
261

262
   ProgressManager::SetProgress(50);
14✔
263
   Log(LogLevel::Info) << "\tConverting states";
14✔
264

265
   hoi4::States states = ConvertStates(source_world,
266
       world_mapper,
267
       world_framework,
268
       vic3_significant_provinces,
269
       world_framework.map_data,
270
       config);
14✔
271

272
   world_framework.strategic_regions.UpdateToMatchNewStates(states.states, world_framework.map_data);
14✔
273

274

275
   std::future<hoi4::Buildings> buildings_future =
276
       std::async(std::launch::async, [&states, &world_framework, &hoi4_mod_filesystem]() {
×
277
          auto result =
278
              ImportBuildings(states, world_framework.coastal_provinces, world_framework.map_data, hoi4_mod_filesystem);
14✔
279
          ProgressManager::AddProgress(5);
14✔
280
          return result;
14✔
281
       });
14✔
282

283
   std::future<hoi4::Railways> railways_future =
284
       std::async(std::launch::async, [&vic3_significant_provinces, &world_mapper, &world_framework, &states]() {
×
285
          // convertRailways logs progress internally
286
          return ConvertRailways(vic3_significant_provinces,
287
              world_mapper.province_mapper,
14✔
288
              world_framework.map_data,
14✔
289
              world_framework.province_definitions,
14✔
290
              states);
14✔
291
       });
14✔
292

293
   Log(LogLevel::Info) << "\tConverting countries";
14✔
294
   ProgressManager::AddProgress(10);
14✔
295

296
   std::map<int, hoi4::Character> characters;
14✔
297
   std::map<std::string, mappers::CultureQueue> culture_queues;
14✔
298
   std::map<std::string, hoi4::Country> countries = ConvertCountries(source_world,
299
       world_mapper,
300
       source_world.GetLocalizations(),
301
       states,
302
       characters,
303
       culture_queues,
304
       config.debug);
14✔
305

306
   Log(LogLevel::Info) << "\tAssigning portraits to characters";
14✔
307
   ProgressManager::AddProgress(5);
14✔
308
   AssignPortraits(culture_queues,
14✔
309
       world_mapper.culture_graphics_mapper,
14✔
310
       source_world.GetCultureDefinitions(),
311
       source_world.GetPlaythroughId(),
312
       characters);
313

314
   std::set<std::string> great_powers =
315
       MapPowers(source_world.GetCountryRankings().GetGreatPowers(), world_mapper.country_mapper);
14✔
316
   std::set<std::string> major_powers =
317
       MapPowers(source_world.GetCountryRankings().GetMajorPowers(), world_mapper.country_mapper);
14✔
318
   MarkCapitalsAsCapitals(countries, states.states);
14✔
319
   IncreaseAirBasesInCapitals(countries, states.states);
14✔
320
   IncreaseVictoryPointsInCapitals(states.states,
14✔
321
       source_world.GetCountryRankings(),
322
       world_mapper.country_mapper,
14✔
323
       countries);
324
   LogVictoryPointData(states.states);
14✔
325
   ProgressManager::AddProgress(5);
14✔
326

327
   ConvertWars(source_world.GetWars(), world_mapper.country_mapper, countries);
14✔
328
   ProgressManager::AddProgress(1);
14✔
329

330
   hoi4::Localizations localizations = ConvertLocalizations(source_world.GetLocalizations(),
331
       world_mapper.country_mapper.GetCountryMappings(),
332
       states.hoi4_state_names_to_vic3_state_names,
333
       source_world.GetStateRegions(),
334
       world_mapper.province_mapper,
14✔
335
       source_world.GetCountries(),
336
       source_world.GetCharacters(),
337
       countries,
338
       characters);
14✔
339

340
   hoi4::Railways railways = railways_future.get();
14✔
341
   hoi4::Buildings buildings = buildings_future.get();
14✔
342
   ProgressManager::AddProgress(5);
14✔
343

344
   hoi4::World world(hoi4::WorldOptions{.countries = countries,
14✔
345
       .great_powers = great_powers,
346
       .major_powers = major_powers,
347
       .states = states,
348
       .strategic_regions = world_framework.strategic_regions,
349
       .buildings = buildings,
350
       .railways = railways,
351
       .localizations = localizations,
352
       .characters = characters});
14✔
353

354
   std::set<DecisionsCategory> decisions_categories;
14✔
355
   std::map<std::string, std::vector<Decision>> decisions_in_categories;
14✔
356
   std::map<std::string, std::vector<Event>> country_events;
14✔
357

358
   const std::map<std::string, Role> roles = ImportRoles();
14✔
359
   std::map<std::string, Country>& modifiable_countries = world.GetModifiableCountries();
14✔
360
   for (const auto& [tag, country_roles]: CreateStories(roles, world, modifiable_countries))
14✔
361
   {
362
      auto country_itr = modifiable_countries.find(tag);
×
363
      if (country_itr == modifiable_countries.end())
×
364
      {
365
         Log(LogLevel::Warning) << fmt::format("Country {} in story could not be found.", tag);
×
366
         continue;
×
367
      }
368

369
      for (const Role& country_role: country_roles)
×
370
      {
371
         for (const DecisionsCategory& role_category: country_role.GetDecisionsCategories())
×
372
         {
373
            decisions_categories.insert(role_category);
×
374
         }
375
         for (const auto& [category, decisions]: country_role.GetDecisionsInCategories())
×
376
         {
377
            decisions_in_categories.emplace(category, decisions);
×
378
         }
379
         for (const Event& event: country_role.GetEvents())
×
380
         {
381
            if (auto [itr, success] = country_events.emplace(tag, std::vector{event}); !success)
×
382
            {
383
               itr->second.push_back(event);
×
384
            }
385
         }
386
      }
387

388
      const FocusTree tree = AssembleTree(country_roles, tag, world);
×
389
      country_itr->second.SetFocusTree(tree);
×
390
   }
14✔
391

392
   world.SetDecisionsCategories(decisions_categories);
14✔
393
   world.SetDecisions(decisions_in_categories);
14✔
394
   world.SetCountryEvents(country_events);
14✔
395

396
   return world;
28✔
397
}
28✔
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