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

ParadoxGameConverters / Vic3ToHoI4 / 28993256854

09 Jul 2026 04:06AM UTC coverage: 92.455% (-0.02%) from 92.478%
28993256854

Pull #816

github

web-flow
Merge f4996d1a2 into a5133ab7f
Pull Request #816: Support Vic3 1.13

28 of 34 new or added lines in 7 files covered. (82.35%)

26346 of 28496 relevant lines covered (92.46%)

48321.1 hits per line

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

99.26
/src/vic3_world/characters/vic3_character_manager.cpp
1
#include "src/vic3_world/characters/vic3_character_manager.h"
2

3
#include <external/commonItems/CommonRegexes.h>
4
#include <external/commonItems/Log.h>
5
#include <external/commonItems/Parser.h>
6
#include <external/commonItems/ParserHelpers.h>
7
#include <external/fmt/include/fmt/format.h>
8

9
#include <ranges>
10

11
#include "src/vic3_world/characters/vic3_characters_importer.h"
12
#include "src/vic3_world/characters/vic3_country_character_map_importer.h"
13

14

15

16
namespace
17
{
18
std::map<int, std::string> ImportExileOriginMap(std::istream& input_stream)
8✔
19
{
20
   std::map<int, std::string> exile_origin_map;
8✔
21
   commonItems::parser map_parser;
8✔
22
   map_parser.registerRegex(commonItems::integerRegex,
16✔
23
       [&exile_origin_map](const std::string& number_string, std::istream& input_stream) {
8✔
24
          const int exile_id = std::stoi(number_string);
13✔
25
          exile_origin_map.emplace(exile_id, commonItems::getString(input_stream));
13✔
26
       });
13✔
27
   map_parser.IgnoreUnregisteredItems();
8✔
28
   map_parser.parseStream(input_stream);
8✔
29

30

31
   Log(LogLevel::Info) << fmt::format("\tFound home countries of {} exiles.", exile_origin_map.size());
8✔
32
   return exile_origin_map;
8✔
33
}
8✔
34
std::map<int, int> ImportCharacterIgMap(std::istream& input_stream)
7✔
35
{
36
   std::map<int, int> character_ig_map;
7✔
37
   commonItems::parser map_parser;
7✔
38
   map_parser.registerRegex(commonItems::integerRegex,
14✔
39
       [&character_ig_map](const std::string& number_string, std::istream& input_stream) {
7✔
40
          const int character_id = std::stoi(number_string);
24✔
41
          character_ig_map.emplace(character_id, commonItems::getInt(input_stream));
24✔
42
       });
24✔
43
   map_parser.IgnoreUnregisteredItems();
7✔
44
   map_parser.parseStream(input_stream);
7✔
45

46
   // Everyone but homeless exiles.
47
   Log(LogLevel::Info) << fmt::format("\tFound IGs for {} characters.", character_ig_map.size());
7✔
48
   return character_ig_map;
7✔
49
}
7✔
50
std::set<int> ImportExilePool(std::istream& input_stream)
6✔
51
{
52
   std::set<int> exile_pool;
6✔
53
   commonItems::parser map_parser;
6✔
54
   map_parser.registerRegex(commonItems::integerRegex,
12✔
55
       [&exile_pool](const std::string& number_string, std::istream& input_stream) {
6✔
56
          exile_pool.emplace(std::stoi(number_string));
7✔
57
          commonItems::ignoreItem("interest_group", input_stream);
7✔
58
       });
7✔
59
   map_parser.IgnoreUnregisteredItems();
6✔
60
   map_parser.parseStream(input_stream);
6✔
61

62
   // Homeless exiles.
63
   Log(LogLevel::Info) << fmt::format("\tFound {} homeless agitators.", exile_pool.size());
6✔
64
   return exile_pool;
6✔
65
}
6✔
66

67
//// For backwards compatibility with pre 1.5 Vic - uses HQs
68
std::set<int> ImportEmployedCommanders(std::istream& input_stream)
7✔
69
{
70
   std::set<int> hired_commanders;
7✔
71
   commonItems::parser map_parser;
7✔
72
   map_parser.registerRegex(commonItems::integerRegex,
14✔
73
       [&hired_commanders]([[maybe_unused]] const std::string& hq_number_string, std::istream& input_stream) {
7✔
74
          std::ranges::copy(commonItems::getInts(input_stream),
13✔
75
              std::inserter(hired_commanders, hired_commanders.begin()));
76
       });
13✔
77
   map_parser.IgnoreUnregisteredItems();
7✔
78
   map_parser.parseStream(input_stream);
7✔
79

80
   Log(LogLevel::Info) << fmt::format("\tFound {} commanders employed in HQs.", hired_commanders.size());
7✔
81
   return hired_commanders;
7✔
82
}
7✔
83
//
84

85
int ImportObituary(std::istream& input_stream)
2✔
86
{
87
   int obituary = 0;
2✔
88
   commonItems::parser map_parser;
2✔
89
   map_parser.registerKeyword("object", [&obituary](std::istream& input_stream) {
6✔
90
      obituary = commonItems::getInt(input_stream);
2✔
91
   });
2✔
92
   map_parser.IgnoreUnregisteredItems();
2✔
93
   map_parser.parseStream(input_stream);
2✔
94

95
   return obituary;
2✔
96
}
2✔
97
std::set<int> ImportObituaries(std::istream& input_stream)
1✔
98
{
99
   std::set<int> obituaries;
1✔
100
   const auto& blobs = commonItems::blobList(input_stream);
1✔
101
   for (const std::string& blob: blobs.getBlobs())
3✔
102
   {
103
      auto obit_stream = std::stringstream(blob);
2✔
104
      obituaries.insert(ImportObituary(obit_stream));
2✔
105
   }
3✔
106
   Log(LogLevel::Info) << fmt::format("\tFound {} dead characters. Hiding the bodies.", obituaries.size());
1✔
107
   return obituaries;
1✔
108
}
1✔
109
}  // namespace
110

111
vic3::CharacterManager::CharacterManager(std::istream& input_stream)
17✔
112
{
113
   character_manager_parser_.registerKeyword("database", [this](std::istream& input_stream) {
51✔
114
      characters_ = ImportCharacters(input_stream);
13✔
115
   });
13✔
116
   character_manager_parser_.registerKeyword("country_character_map", [this](std::istream& input_stream) {
51✔
117
      country_character_map_ = ImportCountryCharacterMap(input_stream);
6✔
118
   });
6✔
119
   character_manager_parser_.registerKeyword("exile_country_map", [this](std::istream& input_stream) {
51✔
120
      exile_origin_map_ = ImportExileOriginMap(input_stream);
8✔
121
   });
8✔
122
   character_manager_parser_.registerKeyword("character_ig_map", [this](std::istream& input_stream) {
51✔
123
      character_ig_map_ = ImportCharacterIgMap(input_stream);
7✔
124
   });
7✔
125
   character_manager_parser_.registerKeyword("home_hq_character_map", [this](std::istream& input_stream) {
51✔
126
      hired_commanders_ = ImportEmployedCommanders(input_stream);
7✔
127
   });
7✔
128
   character_manager_parser_.registerKeyword("dead_objects", [this](std::istream& input_stream) {
51✔
129
      commonItems::parser dead_parser;
1✔
130
      dead_parser.registerKeyword("dead_objects", [this](std::istream& input_stream) {
3✔
131
         obituaries_ = ImportObituaries(input_stream);
1✔
132
      });
1✔
133
      dead_parser.IgnoreUnregisteredItems();
1✔
134
      dead_parser.parseStream(input_stream);
1✔
135
   });
1✔
136
   character_manager_parser_.registerKeyword("exile_pool", [this](std::istream& input_stream) {
51✔
137
      exile_pool_ = ImportExilePool(input_stream);
6✔
138
   });
6✔
139
   character_manager_parser_.IgnoreUnregisteredItems();
17✔
140
   character_manager_parser_.parseStream(input_stream);
17✔
141

142
   AssignHomeTagToExiles();
17✔
143
   AssignIgToCharacters();
17✔
144
   HireCommanders();
17✔
145
}
17✔
146

147
void vic3::CharacterManager::AssignHomeTagToExiles()
17✔
148
{
149
   int count = 0;
17✔
150
   for (auto& character: characters_ | std::views::values)
60✔
151
   {
152
      if (const auto itr = exile_origin_map_.find(character.GetId()); itr != exile_origin_map_.end())
43✔
153
      {
154
         character.SetHomeTag(itr->second);
13✔
155
         ++count;
13✔
156
      }
157
   }
158

159
   Log(LogLevel::Info) << fmt::format("\tFound {} agitators working abroad.", count);
17✔
160
}
17✔
161

162
void vic3::CharacterManager::AssignIgToCharacters()
17✔
163
{
164
   int characters_with_ig = 0;
17✔
165
   int characters_without_ig = 0;
17✔
166
   for (auto& character: characters_ | std::views::values)
60✔
167
   {
168
      if (exile_pool_.contains(character.GetId()))
43✔
169
      {
170
         continue;
5✔
171
      }
172

173
      if (obituaries_.contains(character.GetId()))
38✔
174
      {
175
         continue;
2✔
176
      }
177

178
      if (character.GetIgId() != 0)
36✔
179
      {
NEW
180
         characters_with_ig++;
×
181
      }
182
      else if (const auto itr = character_ig_map_.find(character.GetId()); itr != character_ig_map_.end())
36✔
183
      {
184
         character.SetIgId(itr->second);
24✔
185
         characters_with_ig++;
24✔
186
      }
187
      else
188
      {
189
         characters_without_ig++;
12✔
190
      }
191
   }
192

193
   Log(LogLevel::Info) << fmt::format("\t{} characters are in interest groups. {} are uninteresting.",
34✔
194
       characters_with_ig,
195
       characters_without_ig);
17✔
196
}
17✔
197

198
void vic3::CharacterManager::HireCommanders()
17✔
199
{
200
   for (auto& character: characters_ | std::views::values)
39✔
201
   {
202
      if (character.IsCommander())
28✔
203
      {
204
         break;
6✔
205
      }
206

207
      if (hired_commanders_.contains(character.GetId()))
22✔
208
      {
209
         character.SetCommander();
2✔
210
      }
211
   }
212
}
17✔
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