1 #include "EmpireManager.h"
2
3 #include "Empire.h"
4 #include "../util/Directories.h"
5 #include "../util/GameRules.h"
6 #include "../util/i18n.h"
7 #include "../util/Logger.h"
8 #include "../util/XMLDoc.h"
9 #include "../universe/Enums.h"
10
11 #include <boost/filesystem/fstream.hpp>
12
13 namespace {
14 // sorted pair, so order of empire IDs specified doesn't matter
DiploKey(int id1,int ind2)15 std::pair<int, int> DiploKey(int id1, int ind2)
16 { return std::make_pair(std::max(id1, ind2), std::min(id1, ind2)); }
17
18 const std::string EMPTY_STRING;
19 }
20
EmpireManager()21 EmpireManager::EmpireManager()
22 {}
23
~EmpireManager()24 EmpireManager::~EmpireManager()
25 { Clear(); }
26
operator =(EmpireManager & rhs)27 const EmpireManager& EmpireManager::operator=(EmpireManager& rhs) {
28 Clear();
29 m_empire_map = rhs.m_empire_map;
30 rhs.m_empire_map.clear();
31
32 m_empire_diplomatic_statuses = rhs.m_empire_diplomatic_statuses;
33 rhs.m_empire_diplomatic_statuses.clear();
34
35 m_diplomatic_messages = rhs.m_diplomatic_messages;
36 rhs.m_diplomatic_messages.clear();
37
38 return *this;
39 }
40
GetEmpire(int id) const41 const Empire* EmpireManager::GetEmpire(int id) const {
42 auto it = m_empire_map.find(id);
43 return it == m_empire_map.end() ? nullptr : it->second;
44 }
45
GetSource(int id) const46 std::shared_ptr<const UniverseObject> EmpireManager::GetSource(int id) const {
47 auto it = m_empire_map.find(id);
48 return it != m_empire_map.end() ? it->second->Source() : nullptr;
49 }
50
GetEmpireName(int id) const51 const std::string& EmpireManager::GetEmpireName(int id) const {
52 auto it = m_empire_map.find(id);
53 return it == m_empire_map.end() ? EMPTY_STRING : it->second->Name();
54 }
55
begin() const56 EmpireManager::const_iterator EmpireManager::begin() const
57 { return m_empire_map.begin(); }
58
end() const59 EmpireManager::const_iterator EmpireManager::end() const
60 { return m_empire_map.end(); }
61
NumEmpires() const62 int EmpireManager::NumEmpires() const
63 { return m_empire_map.size(); }
64
NumEliminatedEmpires() const65 int EmpireManager::NumEliminatedEmpires() const {
66 int eliminated_count = 0;
67
68 for (const auto& empire : m_empire_map)
69 if (empire.second->Eliminated())
70 eliminated_count++;
71
72 return eliminated_count;
73 }
74
Dump() const75 std::string EmpireManager::Dump() const {
76 std::string retval = "Empires:\n";
77 for (const auto& entry : m_empire_map)
78 retval += entry.second->Dump();
79 retval += DumpDiplomacy();
80 return retval;
81 }
82
DumpDiplomacy() const83 std::string EmpireManager::DumpDiplomacy() const {
84 std::string retval = "Diplomatic Statuses:\n";
85 for (const auto& entry : m_empire_diplomatic_statuses) {
86 const Empire* empire1 = GetEmpire(entry.first.first);
87 const Empire* empire2 = GetEmpire(entry.first.second);
88 if (!empire1 || !empire2)
89 continue;
90 retval += " * " + empire1->Name() + " / " + empire2->Name() + " : ";
91 switch (entry.second) {
92 case DIPLO_WAR: retval += "War"; break;
93 case DIPLO_PEACE: retval += "Peace"; break;
94 case DIPLO_ALLIED: retval += "Allied"; break;
95 default: retval += "?"; break;
96 }
97 retval += "\n";
98 }
99 retval += "Diplomatic Messages:\n";
100 for (const auto& message : m_diplomatic_messages) {
101 if (message.second.GetType() == DiplomaticMessage::INVALID_DIPLOMATIC_MESSAGE_TYPE)
102 continue; // don't print non-messages and pollute the log files...
103 retval += "From: " + std::to_string(message.first.first)
104 + " to: " + std::to_string(message.first.second)
105 + " message: " + message.second.Dump() + "\n";
106 }
107
108 return retval;
109 }
110
GetEmpire(int id)111 Empire* EmpireManager::GetEmpire(int id) {
112 iterator it = m_empire_map.find(id);
113 return it == end() ? nullptr : it->second;
114 }
115
begin()116 EmpireManager::iterator EmpireManager::begin()
117 { return m_empire_map.begin(); }
118
end()119 EmpireManager::iterator EmpireManager::end()
120 { return m_empire_map.end(); }
121
BackPropagateMeters()122 void EmpireManager::BackPropagateMeters() {
123 for (auto& entry : m_empire_map)
124 entry.second->BackPropagateMeters();
125 }
126
CreateEmpire(int empire_id,const std::string & name,const std::string & player_name,const GG::Clr & color,bool authenticated)127 Empire* EmpireManager::CreateEmpire(int empire_id, const std::string& name,
128 const std::string& player_name,
129 const GG::Clr& color, bool authenticated)
130 {
131 Empire* empire = new Empire(name, player_name, empire_id, color, authenticated);
132 InsertEmpire(empire);
133 return empire;
134 }
135
InsertEmpire(Empire * empire)136 void EmpireManager::InsertEmpire(Empire* empire) {
137 if (!empire) {
138 ErrorLogger() << "EmpireManager::InsertEmpire passed null empire";
139 return;
140 }
141
142 int empire_id = empire->EmpireID();
143
144 if (m_empire_map.count(empire_id)) {
145 ErrorLogger() << "EmpireManager::InsertEmpire passed empire with id (" << empire_id << ") for which there already is an empire.";
146 return;
147 }
148
149 m_empire_map[empire_id] = empire;
150 }
151
Clear()152 void EmpireManager::Clear() {
153 for (auto& entry : m_empire_map)
154 delete entry.second;
155 m_empire_map.clear();
156 m_empire_diplomatic_statuses.clear();
157 }
158
GetDiplomaticStatus(int empire1,int empire2) const159 DiplomaticStatus EmpireManager::GetDiplomaticStatus(int empire1, int empire2) const {
160 if (empire1 == ALL_EMPIRES || empire2 == ALL_EMPIRES || empire1 == empire2)
161 return INVALID_DIPLOMATIC_STATUS;
162
163 auto it = m_empire_diplomatic_statuses.find(DiploKey(empire1, empire2));
164 if (it != m_empire_diplomatic_statuses.end())
165 return it->second;
166 ErrorLogger() << "Couldn't find diplomatic status between empires " << empire1 << " and " << empire2;
167 return INVALID_DIPLOMATIC_STATUS;
168 }
169
GetEmpireIDsWithDiplomaticStatusWithEmpire(int empire_id,DiplomaticStatus diplo_status) const170 std::set<int> EmpireManager::GetEmpireIDsWithDiplomaticStatusWithEmpire(
171 int empire_id, DiplomaticStatus diplo_status) const
172 {
173 std::set<int> retval;
174 if (empire_id == ALL_EMPIRES || diplo_status == INVALID_DIPLOMATIC_STATUS)
175 return retval;
176 // find ids of empires with the specified diplomatic status with the specified empire
177 for (auto const& id_pair_status : m_empire_diplomatic_statuses) {
178 if (id_pair_status.second != diplo_status)
179 continue;
180 if (id_pair_status.first.first == empire_id)
181 retval.insert(id_pair_status.first.second);
182 else if (id_pair_status.first.second == empire_id)
183 retval.insert(id_pair_status.first.first);
184 }
185 return retval;
186 }
187
DiplomaticMessageAvailable(int sender_id,int recipient_id) const188 bool EmpireManager::DiplomaticMessageAvailable(int sender_id, int recipient_id) const {
189 auto it = m_diplomatic_messages.find({sender_id, recipient_id});
190 return it != m_diplomatic_messages.end() &&
191 it->second.GetType() != DiplomaticMessage::INVALID_DIPLOMATIC_MESSAGE_TYPE;
192 }
193
GetDiplomaticMessage(int sender_id,int recipient_id) const194 const DiplomaticMessage& EmpireManager::GetDiplomaticMessage(int sender_id, int recipient_id) const {
195 auto it = m_diplomatic_messages.find({sender_id, recipient_id});
196 if (it != m_diplomatic_messages.end())
197 return it->second;
198 static DiplomaticMessage DEFAULT_DIPLOMATIC_MESSAGE;
199 //WarnLogger() << "Couldn't find requested diplomatic message between empires " << sender_id << " and " << recipient_id;
200 return DEFAULT_DIPLOMATIC_MESSAGE;
201 }
202
SetDiplomaticStatus(int empire1,int empire2,DiplomaticStatus status)203 void EmpireManager::SetDiplomaticStatus(int empire1, int empire2, DiplomaticStatus status) {
204 DiplomaticStatus initial_status = GetDiplomaticStatus(empire1, empire2);
205 if (status != initial_status) {
206 m_empire_diplomatic_statuses[DiploKey(empire1, empire2)] = status;
207 DiplomaticStatusChangedSignal(empire1, empire2);
208 }
209 }
210
SetDiplomaticMessage(const DiplomaticMessage & message)211 void EmpireManager::SetDiplomaticMessage(const DiplomaticMessage& message) {
212 int empire1 = message.SenderEmpireID();
213 int empire2 = message.RecipientEmpireID();
214 const DiplomaticMessage& initial_message = GetDiplomaticMessage(empire1, empire2);
215 if (message != initial_message) {
216 m_diplomatic_messages[{empire1, empire2}] = message;
217 DiplomaticMessageChangedSignal(empire1, empire2);
218 }
219 }
220
RemoveDiplomaticMessage(int sender_id,int recipient_id)221 void EmpireManager::RemoveDiplomaticMessage(int sender_id, int recipient_id) {
222 auto it = m_diplomatic_messages.find({sender_id, recipient_id});
223 bool changed = (it != m_diplomatic_messages.end()) &&
224 (it->second.GetType() != DiplomaticMessage::INVALID_DIPLOMATIC_MESSAGE_TYPE);
225
226 m_diplomatic_messages[{sender_id, recipient_id}] =
227 DiplomaticMessage(sender_id, recipient_id, DiplomaticMessage::INVALID_DIPLOMATIC_MESSAGE_TYPE);
228
229 // if there already was a message, and it wasn't already a non-message, notify about change
230 if (changed)
231 DiplomaticMessageChangedSignal(sender_id, recipient_id);
232 }
233
HandleDiplomaticMessage(const DiplomaticMessage & message)234 void EmpireManager::HandleDiplomaticMessage(const DiplomaticMessage& message) {
235 int sender_empire_id = message.SenderEmpireID();
236 int recipient_empire_id = message.RecipientEmpireID();
237
238 if (!message.IsAllowed())
239 return;
240
241 DiplomaticStatus diplo_status = GetDiplomaticStatus(sender_empire_id, recipient_empire_id);
242 bool message_from_recipient_to_sender_available = DiplomaticMessageAvailable(recipient_empire_id, sender_empire_id);
243 const DiplomaticMessage& existing_message_from_recipient_to_sender = GetDiplomaticMessage(recipient_empire_id, sender_empire_id);
244 //bool message_from_sender_to_recipient_available = DiplomaticMessageAvailable(sender_empire_id, recipient_empire_id);
245
246 switch (message.GetType()) {
247 case DiplomaticMessage::WAR_DECLARATION: {
248 if (diplo_status == DIPLO_PEACE) {
249 // cancels any previous messages, sets empires at war
250 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
251 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
252 SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_WAR);
253 }
254 break;
255 }
256
257 case DiplomaticMessage::PEACE_PROPOSAL: {
258 if (diplo_status == DIPLO_WAR && !message_from_recipient_to_sender_available) {
259 SetDiplomaticMessage(message);
260
261 } else if (diplo_status == DIPLO_WAR && message_from_recipient_to_sender_available) {
262 if (existing_message_from_recipient_to_sender.GetType() ==
263 DiplomaticMessage::PEACE_PROPOSAL)
264 {
265 // somehow multiple peace proposals sent by players to eachother
266 // cancel and remove
267 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
268 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
269 SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_PEACE);
270 }
271 }
272 break;
273 }
274
275 case DiplomaticMessage::ACCEPT_PEACE_PROPOSAL: {
276 if (message_from_recipient_to_sender_available &&
277 existing_message_from_recipient_to_sender.GetType() == DiplomaticMessage::PEACE_PROPOSAL)
278 {
279 // one player proposed peace and the other accepted
280 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
281 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
282 SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_PEACE);
283 }
284 break;
285 }
286
287 case DiplomaticMessage::ALLIES_PROPOSAL: {
288 if (diplo_status == DIPLO_PEACE && !message_from_recipient_to_sender_available) {
289 SetDiplomaticMessage(message);
290
291 } else if (diplo_status == DIPLO_PEACE && message_from_recipient_to_sender_available) {
292 if (existing_message_from_recipient_to_sender.GetType() ==
293 DiplomaticMessage::ALLIES_PROPOSAL)
294 {
295 // somehow multiple allies proposals sent by players to eachother
296 // cancel and remove
297 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
298 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
299 SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_ALLIED);
300 }
301 }
302 break;
303 }
304
305 case DiplomaticMessage::ACCEPT_ALLIES_PROPOSAL: {
306 if (message_from_recipient_to_sender_available &&
307 existing_message_from_recipient_to_sender.GetType() == DiplomaticMessage::ALLIES_PROPOSAL)
308 {
309 // one player proposed alliance and the other accepted
310 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
311 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
312 SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_ALLIED);
313 }
314 break;
315 }
316
317 case DiplomaticMessage::END_ALLIANCE_DECLARATION: {
318 if (diplo_status == DIPLO_ALLIED) {
319 // cancels any previous messages, sets empires to peace
320 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
321 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
322 SetDiplomaticStatus(sender_empire_id, recipient_empire_id, DIPLO_PEACE);
323 }
324 break;
325 }
326
327 case DiplomaticMessage::CANCEL_PROPOSAL: {
328 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
329 break;
330 }
331
332 case DiplomaticMessage::REJECT_PROPOSAL: {
333 RemoveDiplomaticMessage(sender_empire_id, recipient_empire_id);
334 RemoveDiplomaticMessage(recipient_empire_id, sender_empire_id);
335 break;
336 }
337
338 default:
339 break;
340 }
341 }
342
ResetDiplomacy()343 void EmpireManager::ResetDiplomacy() {
344 // remove messages
345 m_diplomatic_messages.clear();
346
347 // set all empires at war with each other (but not themselves)
348 m_empire_diplomatic_statuses.clear();
349 for (auto id_empire_1 : m_empire_map) {
350 for (auto id_empire_2 : m_empire_map) {
351 if (id_empire_1.first == id_empire_2.first)
352 continue;
353 const std::pair<int, int> diplo_key = DiploKey(id_empire_1.first, id_empire_2.first);
354 m_empire_diplomatic_statuses[diplo_key] = DIPLO_WAR;
355 }
356 }
357 }
358
GetDiplomaticMessagesToSerialize(std::map<std::pair<int,int>,DiplomaticMessage> & messages,int encoding_empire) const359 void EmpireManager::GetDiplomaticMessagesToSerialize(std::map<std::pair<int, int>, DiplomaticMessage>& messages,
360 int encoding_empire) const
361 {
362 messages.clear();
363
364 // return all messages for general case
365 if (encoding_empire == ALL_EMPIRES) {
366 messages = m_diplomatic_messages;
367 return;
368 }
369
370 // find all messages involving encoding empire
371 for (const auto& entry : m_diplomatic_messages) {
372 if (entry.first.first == encoding_empire || entry.first.second == encoding_empire)
373 messages.insert(entry);
374 }
375 }
376
EmpireColorsNonConst()377 std::vector<GG::Clr>& EmpireColorsNonConst() {
378 static std::vector<GG::Clr> colors;
379 return colors;
380 }
381
InitEmpireColors(const boost::filesystem::path & path)382 void InitEmpireColors(const boost::filesystem::path& path) {
383 auto& colors = EmpireColorsNonConst();
384
385 XMLDoc doc;
386
387 boost::filesystem::ifstream ifs(path);
388 if (ifs) {
389 doc.ReadDoc(ifs);
390 ifs.close();
391 } else {
392 ErrorLogger() << "Unable to open data file " << path.filename();
393 return;
394 }
395
396 for (const XMLElement& elem : doc.root_node.children) {
397 try {
398 std::string hex_colour("#");
399 hex_colour.append(elem.attributes.at("hex"));
400 colors.push_back(GG::HexClr(hex_colour));
401 } catch(const std::exception& e) {
402 ErrorLogger() << "empire_colors.xml: " << e.what() << std::endl;
403 }
404 }
405 }
EmpireColors()406 const std::vector<GG::Clr>& EmpireColors() {
407 auto& colors = EmpireColorsNonConst();
408 if (colors.empty()) {
409 colors = { GG::Clr( 0, 255, 0, 255), GG::Clr( 0, 0, 255, 255), GG::Clr(255, 0, 0, 255),
410 GG::Clr( 0, 255, 255, 255), GG::Clr(255, 255, 0, 255), GG::Clr(255, 0, 255, 255)};
411 }
412 return colors;
413 }
414