Symphony Of Empires
minimap.cpp
Go to the documentation of this file.
1 // Symphony of Empires
2 // Copyright (C) 2021, Symphony of Empires contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // client/interface/minimap.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include <unordered_map>
26 #include "eng3d/string.hpp"
27 #include "eng3d/texture.hpp"
28 #include "eng3d/ui/button.hpp"
29 #include "eng3d/ui/close_button.hpp"
30 #include "eng3d/ui/image.hpp"
31 #include "eng3d/ui/tooltip.hpp"
32 #include "eng3d/ui/div.hpp"
33 #include "eng3d/ui/label.hpp"
34 #include "eng3d/ui/table.hpp"
35 
37 #include "client/map.hpp"
38 #include "world.hpp"
39 #include "server/ai.hpp"
40 #include "server/economy.hpp"
41 
42 using namespace Interface;
43 
47  std::function<float(const World&, ProvinceId)> province_value,
50 std::vector<ProvinceColor> terrain_map_mode(const World& world);
57 std::vector<ProvinceColor> religion_map_mode(const World& world);
58 std::string religion_tooltip(const World& world, const ProvinceId id);
59 std::vector<ProvinceColor> language_map_mode(const World& world);
60 std::string language_tooltip(const World& world, const ProvinceId id);
61 std::vector<ProvinceColor> population_map_mode(const World& world);
62 std::string population_tooltip(const World& world, const ProvinceId id);
63 
64 Minimap::Minimap(GameState& _gs, int _x, int _y, UI::Origin _origin)
65  : UI::Window(_x, _y, 400, 200),
66  gs{ _gs }
67 {
68  this->origin = _origin;
69  this->is_pinned = true;
70  this->is_scroll = false;
71  this->padding = glm::ivec2(0, 24);
72 
73  auto& flex_column1 = this->make_widget<UI::Div>(5, 5, 24, 190);
74  flex_column1.flex = UI::Flex::COLUMN;
75  flex_column1.flex_align = UI::Align::CENTER;
76  auto& flex_column2 = this->make_widget<UI::Div>(35, 5, 24, 190);
77  flex_column2.flex = UI::Flex::COLUMN;
78  flex_column2.flex_align = UI::Align::CENTER;
79 
80  auto& flat_btn = flex_column1.make_widget<UI::Image>(0, 0, 24, 24, "gfx/flat_icon.png");
81  flat_btn.set_on_click([this](UI::Widget&) {
82  this->gs.map->set_view(MapView::PLANE_VIEW);
83  });
84  flat_btn.set_tooltip("Flat map");
85 
86  auto& globe_btn = flex_column2.make_widget<UI::Image>(0, 0, 24, 24, "gfx/globe_icon.png");
87  globe_btn.set_on_click([this](UI::Widget&) {
88  this->gs.map->set_view(MapView::SPHERE_VIEW);
89  });
90  globe_btn.set_tooltip("Globe map");
91 
92  auto& landscape_ibtn = flex_column1.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
93  landscape_ibtn.set_on_click([this](UI::Widget&) {
94  this->gs.map->set_selection(nullptr);
95  this->gs.map->set_map_mode(terrain_map_mode, empty_province_tooltip);
96  set_mapmode_options(nullptr);
97  });
98  landscape_ibtn.set_tooltip("Terrain");
99 
100  auto& political_ibtn = flex_column1.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
101  political_ibtn.set_on_click([this](UI::Widget&) {
102  this->gs.map->set_selection(nullptr);
103  this->gs.map->set_map_mode(political_map_mode, political_province_tooltip);
104  set_mapmode_options(nullptr);
105  });
106  political_ibtn.set_tooltip("Political");
107 
108  auto& relations_ibtn = flex_column1.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
109  relations_ibtn.set_on_click([this](UI::Widget&) {
110  this->gs.map->set_selection([](const World&, Map& map, const Province& province) {
111  NationId nation_id = province.owner_id;
112  mapmode_generator map_mode = relations_map_mode(nation_id);
113  mapmode_tooltip map_tooltip = relations_tooltip(nation_id);
114  map.set_map_mode(map_mode, map_tooltip);
115  });
116  const auto nation_id = this->gs.curr_nation->get_id();
117  mapmode_generator map_mode = relations_map_mode(nation_id);
118  mapmode_tooltip map_tooltip = relations_tooltip(nation_id);
119  this->gs.map->set_map_mode(map_mode, map_tooltip);
120  set_mapmode_options(nullptr);
121  });
122  relations_ibtn.set_tooltip("Relations");
123 
124  auto& transport_cost_ibtn = flex_column1.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
125  transport_cost_ibtn.set_on_click([this](UI::Widget&) {
126  this->gs.map->set_selection([](const World&, Map& map, const Province& selected_province) {
127  map.set_map_mode(trade_map_mode(selected_province), trade_tooltip(selected_province));
128  });
129  set_mapmode_options(nullptr);
130  });
131  transport_cost_ibtn.set_tooltip("Transport cost");
132 
133  auto& population_ibtn = flex_column1.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
134  population_ibtn.set_on_click([this](UI::Widget&) {
135  this->gs.map->set_selection(nullptr);
136  this->gs.map->set_map_mode(population_map_mode, population_tooltip);
137  set_mapmode_options(nullptr);
138  });
139  population_ibtn.set_tooltip("Population");
140 
141  auto& terrain_color_ibtn = flex_column2.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
142  terrain_color_ibtn.set_on_click([this](UI::Widget&) {
143  this->gs.map->set_selection(nullptr);
144  mapmode_generator map_mode = [](const World& world) {
145  std::vector<ProvinceColor> province_color;
146  for(unsigned int i = 0; i < world.provinces.size(); i++) {
147  const auto& province = world.provinces[i];
148  Eng3D::Color color = Eng3D::Color::bgr32(world.terrain_types[province.terrain_type_id].color);
149  province_color.emplace_back(ProvinceId(i), color);
150  }
151  province_color.emplace_back(ProvinceId(-2), Eng3D::Color{}); // Water
152  province_color.emplace_back(ProvinceId(-1), Eng3D::Color{}); // Land
153  return province_color;
154  };
155  mapmode_tooltip map_tooltip = [](const World& world, const ProvinceId id) -> std::string {
156  return world.terrain_types[world.provinces[id].terrain_type_id].name;
157  };
158  this->gs.map->set_map_mode(map_mode, map_tooltip);
159  set_mapmode_options(nullptr);
160  });
161  terrain_color_ibtn.set_tooltip("Simple terrain");
162 
163  auto& language_ibtn = flex_column2.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
164  language_ibtn.set_on_click([this](UI::Widget&) {
165  this->gs.map->set_selection(nullptr);
166  // this->gs.map->set_map_mode(map_mode, map_tooltip);
167  this->gs.map->set_map_mode(language_map_mode, language_tooltip);
168  set_mapmode_options(nullptr);
169  });
170  language_ibtn.set_tooltip("Language diversity");
171 
172  auto& religion_ibtn = flex_column2.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
173  religion_ibtn.set_on_click([this](UI::Widget&) {
174  this->gs.map->set_selection(nullptr);
175  this->gs.map->set_map_mode(religion_map_mode, religion_tooltip);
176  set_mapmode_options(nullptr);
177  });
178  religion_ibtn.set_tooltip("Religion");
179 
180  auto& commodity_price_ibtn = flex_column2.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
181  commodity_price_ibtn.set_on_click([this](UI::Widget&) {
182  this->gs.map->set_selection(nullptr);
183  set_mapmode_options(new MapmodeCommodityOptions(this->gs));
184  });
185  commodity_price_ibtn.set_tooltip("Commodity");
186 
187  auto& militancy_ibtn = flex_column2.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
188  militancy_ibtn.set_on_click([this](UI::Widget&) {
189  this->gs.map->set_selection([](const World&, Map& map, const Province& selected_province) {
190  map.set_map_mode(([](ProvinceId id) {
191  return [id](const World& world) {
192  const auto& province = world.provinces[id];
193  const auto& nation = world.nations[province.owner_id];
194  const auto& ai = ai_man[nation];
195 
196  auto max_amount = 0.f;
197  for(const auto& province : world.provinces)
198  max_amount = glm::max(ai.potential_risk[province], max_amount);
199 
200  // Mix each color depending of how many live there compared to max_amount
201  auto min = Eng3D::Color::rgb8(128, 128, 255);
202  auto max = Eng3D::Color::rgb8(255, 64, 64);
203  std::vector<ProvinceColor> province_color;
204  for(const auto& province : world.provinces) {
205  auto ratio = province.average_militancy();
206  province_color.emplace_back(province.get_id(), Eng3D::Color::lerp(min, max, ratio));
207  }
208  return province_color;
209  };
210  })(selected_province),
211  ([](ProvinceId province_id) {
212  return [province_id](const World& world, const ProvinceId id) -> std::string {
213  const auto& province = world.provinces[id];
214  return translate_format("Average militancy: %.2f", province.average_militancy());
215  };
216  })(selected_province));
217  });
218  set_mapmode_options(nullptr);
219  });
220  militancy_ibtn.set_tooltip("Militancy");
221 
222  auto& debug_ibtn = flex_column2.make_widget<UI::Image>(0, 0, 24, 24, "gfx/icon.png");
223  debug_ibtn.set_on_click([this](UI::Widget&) {
224  this->gs.map->set_selection([](const World&, Map& map, const Province& selected_province) {
225  map.set_map_mode(([](ProvinceId id) {
226  return [id](const World& world) {
227  const auto& province = world.provinces[id];
228  const auto& nation = world.nations[province.owner_id];
229  const auto& ai = ai_man[nation];
230 
231  auto max_amount = 0.f;
232  for(const auto& province : world.provinces)
233  max_amount = glm::max(ai.potential_risk[province], max_amount);
234 
235  // Mix each color depending of how many live there compared to max_amount
236  auto min = Eng3D::Color::rgb8(128, 128, 255);
237  auto max = Eng3D::Color::rgb8(255, 64, 64);
238  std::vector<ProvinceColor> province_color;
239  for(const auto& province : world.provinces) {
240  auto ratio = ai.potential_risk[province] / max_amount;
241  province_color.emplace_back(province.get_id(), Eng3D::Color::lerp(min, max, ratio));
242  }
243  return province_color;
244  };
245  })(selected_province),
246  ([](ProvinceId province_id) {
247  return [province_id](const World& world, const ProvinceId id) -> std::string {
248  const auto& province = world.provinces[id];
249  const auto& nation = world.nations[province.owner_id];
250  const auto& ai = ai_man[nation];
251  return translate_format("Potential risk: %.2f (Our strenght: %.2f)\nWar weight: %.2f\nUnit battle weight: %.2f\nUnit exist weight: %.2f\nCoastal weight: %.2f\nReconquer weight: %.2f\nStrength threshold: %.2f\nErratic: %.2f\nOverride threshold: %.2f\nGains/losses: %zu/%zu\nMilitary strength: %.2f", ai.potential_risk[province], ai.military_strength, ai.war_weight, ai.unit_battle_weight, ai.unit_exist_weight, ai.coastal_weight, ai.reconquer_weight, ai.strength_threshold, ai.erratic, ai.override_threshold, ai.gains, ai.losses);
252  };
253  })(selected_province));
254  });
255  set_mapmode_options(nullptr);
256  });
257  debug_ibtn.set_tooltip("Debug");
258 
259  this->make_widget<UI::Image>(65, 5, 332, 166, gs.tex_man.load(gs.package_man.get_unique("gfx/minimap.png")));
260 }
261 
262 void Minimap::set_mapmode_options(Widget* widget) {
263  if(mapmode_options)
264  mapmode_options->kill();
265  mapmode_options = widget;
266 }
267 
268 
269 void MapmodeCommodityOptions::update_map_mode() {
270  this->gs.current_mode = MapMode::NORMAL;
271  mapmode_generator map_mode = generic_map_mode(this->province_value);
272  mapmode_tooltip map_tooltip = commodity_tooltip(this->commodity_id);
273  this->gs.map->set_map_mode(map_mode, map_tooltip);
274 }
275 
277  : UI::Div(-200, -300, 200, 500, nullptr),
278  gs{ _gs }
279 {
281  this->current_texture = gs.tex_man.load(gs.package_man.get_unique("gfx/window_background.png"));
282 
283  auto border_tex = gs.tex_man.load(gs.package_man.get_unique("gfx/border2.png"));
284  this->border = UI::Border(border_tex, { 4, 4 }, { 10, 10 });
285  this->flex = UI::Flex::COLUMN;
286 
287  this->province_value = [this](const World& world, ProvinceId id) {
288  const auto& product = world.provinces[id].products[this->commodity_id];
289  return product.price;
290  };
291 
292  auto& price_btn = this->make_widget<UI::Button>(0, 0, 125, 24);
293  price_btn.set_text("Price");
294  price_btn.set_on_click([this](UI::Widget&) {
295  this->province_value = [this](const World& world, ProvinceId id) {
296  const auto& product = world.provinces[id].products[this->commodity_id];
297  return product.price;
298  };
299  update_map_mode();
300  });
301  auto& demand_btn = this->make_widget<UI::Button>(0, 0, 125, 24);
302  demand_btn.set_text("Demand");
303  demand_btn.set_on_click([this](UI::Widget&) {
304  this->province_value = [this](const World& world, ProvinceId id) {
305  const auto& product = world.provinces[id].products[this->commodity_id];
306  return product.demand;
307  };
308  update_map_mode();
309  });
310  auto& supply_btn = this->make_widget<UI::Button>(0, 0, 125, 24);
311  supply_btn.set_text("Supply");
312  supply_btn.set_on_click([this](UI::Widget&) {
313  this->province_value = [this](const World& world, ProvinceId id) {
314  const auto& product = world.provinces[id].products[this->commodity_id];
315  return product.supply;
316  };
317  update_map_mode();
318  });
319  auto& price_delta_btn = this->make_widget<UI::Button>(0, 0, 125, 24);
320  price_delta_btn.set_text("Price change");
321  price_delta_btn.set_on_click([this](UI::Widget&) {
322  this->province_value = [this](const World& world, ProvinceId id) {
323  const auto& product = world.provinces[id].products[this->commodity_id];
324  return product.price_delta;
325  };
326  update_map_mode();
327  });
328  auto& production_btn = this->make_widget<UI::Button>(0, 0, 125, 24);
329  production_btn.set_text("Production");
330  production_btn.set_on_click([this](UI::Widget&) {
331  this->province_value = [this](const World& world, ProvinceId id) {
332  const auto& province = world.provinces[id];
333  const auto& product = province.products[this->commodity_id];
334  auto total = 0.f;
335  for(const auto& building_type : world.building_types)
336  if (building_type.output_id == this->commodity_id)
337  total += province.buildings[building_type].get_output_amount();
338  return total;
339  };
340  update_map_mode();
341  });
342 
343  std::vector<int> sizes{ 160 };
344  std::vector<std::string> header{ "Goods" };
345  auto& table = this->make_widget<UI::Table<CommodityId::Type>>(4, 4, 400 - 8, 35, sizes, header);
346  for(const auto& commodity : gs.world->commodities) {
347  auto& row = table.get_row(commodity);
348  auto commodity_row = row.get_element(0);
349  commodity_row->flex = UI::Flex::ROW;
350  auto good_str = Eng3D::Locale::translate(commodity.name.get_string());
351  auto good_tex = gs.tex_man.load(gs.package_man.get_unique(commodity.get_icon_path()));
352  commodity_row->make_widget<UI::Image>(0, 0, 35, 35, good_tex);
353  commodity_row->make_widget<UI::Label>(0, 0, good_str);
354  commodity_row->set_key(good_str);
355  row.set_on_click([this, commodity](UI::Widget&) {
356  this->commodity_id = commodity.get_id();
357  update_map_mode();
358  });
359  }
360  update_map_mode();
361 }
362 
364  return [good_id](const World& world, const ProvinceId id) -> std::string {
365  const auto& province = world.provinces[id];
366  const auto& product = province.products[good_id];
367 
368  auto total_production = 0.f;
369  for(const auto& building_type : world.building_types)
370  if (building_type.output_id == good_id)
371  total_production += province.buildings[building_type].get_output_amount();
372 
373  std::string str = Eng3D::translate_format(
374  "%s,\nPrice %.2f\nGlobal demand %.2f\nDemand %.2f (Sold today %.2f)\nSupply %.2f (Produced today %.2f)\nProduction %.2f\n",
375  province.name.c_str(), product.price, product.global_demand, product.demand, product.bought, product.supply, product.produced, total_production);
376  for(const auto& building_type : world.building_types) {
377  const auto& building = province.buildings[building_type];
378  if(building.level)
379  str += translate_format("%s (level %.0f), scale %.0f, workers %.0f, budget %.0f\n", building_type.name.c_str(), building.level, building.production_scale, building.workers, building.budget);
380  }
381  return str;
382  };
383 }
384 
386  std::function<float(const World&, ProvinceId)> province_value,
387  Eng3D::Color min_col, Eng3D::Color max_col)
388 {
389  return [province_value, min_col, max_col](const World& world) {
390  std::vector<std::pair<ProvinceId, float>> province_amounts;
391  auto max_value = glm::epsilon<float>();
392  for(auto const& province : world.provinces) {
393  auto id = province.get_id();
394  // Use logaritmic scaling, could be a setting later if needed
395  float value = std::log2f(province_value(world, id) + 1.f);
396  max_value = glm::max(value, max_value);
397  province_amounts.emplace_back(id, value);
398  }
399 
400  // Mix each color by comparing the province value to max_value
401  std::vector<ProvinceColor> province_color;
402  for(auto const& [prov_id, value] : province_amounts) {
403  auto ratio = value / max_value;
404  Eng3D::Color color = Eng3D::Color::lerp(min_col, max_col, ratio);
405  province_color.push_back(ProvinceColor(prov_id, color));
406  }
407  return province_color;
408  };
409 }
410 
411 #include "eng3d/utils.hpp"
413  return [id](const World& world) {
414  std::vector<ProvinceColor> provinces_color;
415  const auto& nation = world.nations[id];
416  for(size_t i = 0; i < world.provinces.size(); i++) {
417  const auto& province = world.provinces[i];
418  if(province.controller_id == nation || world.nations[province.controller_id].is_puppeted_by(nation)) {
419  auto color = Eng3D::Color::rgb8(0x00, 0x00, 0xff);
420  provinces_color.emplace_back(ProvinceId(i), color);
421  continue;
422  }
423 
424  const auto& relation = world.get_relation(province.controller_id, id);
425  const uint8_t r = relation.relation < 0.f ? -relation.relation : 0;
426  const uint8_t g = relation.relation > 0.f ? relation.relation : 0;
427  const uint8_t b = relation.is_allied() ? 0x80 : 0;
428  auto color = Eng3D::Color::rgb8(r, g, b);
429  provinces_color.emplace_back(ProvinceId(i), color);
430  }
431  return provinces_color;
432  };
433 }
434 
436  return [nation_id](const World& world, const ProvinceId id) -> std::string {
437  const auto& province = world.provinces[id];
438  const auto& province_controller = world.nations[province.controller_id];
439  std::string str;
440 
441  if(province.controller_id == province.owner_id) {
442  str += province_controller.get_client_hint().name;
443  } else {
444  str += translate_format("Province owned by %s and controlled by %s", world.nations[province.owner_id].get_client_hint().name.c_str(), province_controller.get_client_hint().name.c_str());
445  }
446 
447  if(province_controller.is_puppeted) {
448  str += string_format("\nPuppet of %s", world.nations[province_controller.puppet_master_id].get_client_hint().name.c_str());
449  return str;
450  }
451 
452  if(province.controller_id != nation_id) {
453  const auto& nation = world.nations[province.controller_id];
454  const auto& relation = world.get_relation(nation, nation_id);
455  if(relation.is_allied()) {
456  str += string_format("\nAllied with %s", nation.get_client_hint().name.c_str());
457  } else if(relation.has_war) {
458  str += string_format("\nAt war with %s", nation.get_client_hint().name.c_str());
459  }
460 
461  static std::array<std::string, 7> rel_lvls = {
462  "unfriendly",
463  "uncordial",
464  "discorteous",
465  "neutral",
466  "respectful",
467  "cordial",
468  "friendly"
469  };
470 
471  size_t idx = (1.f + relation.relation) * rel_lvls.size();
472  str += string_format("\n%.2f%% - %s", relation.relation * 100.f, rel_lvls[idx % rel_lvls.size()].c_str());
473 
474  nation.get_allies([&](const auto& _nation) {
475  str += string_format("%s,", _nation.get_client_hint().name.c_str());
476  });
477  }
478  return str;
479  };
480 }
481 
482 std::vector<ProvinceColor> terrain_map_mode(const World& world) {
483  std::vector<ProvinceColor> province_color;
484  for(size_t i = 0; i < world.provinces.size(); i++)
485  province_color.emplace_back(ProvinceId(i), Eng3D::Color{});
486  province_color.emplace_back(ProvinceId(-2), Eng3D::Color{}); // Water
487  province_color.emplace_back(ProvinceId(-1), Eng3D::Color{}); // Land
488  return province_color;
489 }
490 
491 std::vector<ProvinceColor> religion_map_mode(const World& world) {
492  std::vector<ProvinceColor> province_color;
493  auto min = Eng3D::Color::rgb8(255, 255, 255);
494  for(size_t i = 0; i < world.provinces.size(); i++) {
495  const auto& province = world.provinces[i];
496  std::vector<size_t> religion_amounts(world.religions.size());
497  size_t total_amount = province.total_pops();
498  size_t max_amount = 0;
499  size_t max_religion_id = 0;
500  for(const auto& religion : world.religions) {
501  religion_amounts[religion] = province.religions[religion] * total_amount;
502  size_t amount = religion_amounts[religion];
503  if(amount > max_amount) {
504  max_amount = amount;
505  max_religion_id = religion;
506  }
507  }
508  const auto max = Eng3D::Color::bgr32(world.religions[max_religion_id].color);
509  const auto color = Eng3D::Color::lerp(min, max, ((float)max_amount) / total_amount);
510  province_color.emplace_back(ProvinceId(i), color);
511  }
512  province_color.emplace_back(ProvinceId(-2), Eng3D::Color(0.f, 0.f, 0.f)); // Water
513  province_color.emplace_back(ProvinceId(-1), Eng3D::Color(0.8f, 0.8f, 0.8f)); // Land
514  return province_color;
515 }
516 
517 std::string religion_tooltip(const World& world, const ProvinceId id) {
518  const auto& province = world.provinces[id];
519  const auto it = std::max_element(province.religions.begin(), province.religions.end());
520  return world.religions[std::distance(province.religions.begin(), it)].name;
521 }
522 
523 std::vector<ProvinceColor> language_map_mode(const World& world) {
524  std::vector<ProvinceColor> province_color;
525  const auto min = Eng3D::Color::rgb8(255, 255, 255);
526  for(size_t i = 0; i < world.provinces.size(); i++) {
527  const auto& province = world.provinces[i];
528  std::vector<size_t> language_amounts(world.languages.size());
529  size_t total_amount = province.total_pops();
530  size_t max_amount = 0;
531  size_t max_language_id = 0;
532  for(const auto& language : world.languages) {
533  language_amounts[language] = province.languages[language] * total_amount;
534  size_t amount = language_amounts[language];
535  if(amount > max_amount) {
536  max_amount = amount;
537  max_language_id = language;
538  }
539  }
540  const auto max = Eng3D::Color::bgr32(world.languages[max_language_id].color);
541  const auto color = Eng3D::Color::lerp(min, max, ((float)max_amount) / total_amount);
542  province_color.emplace_back(ProvinceId(i), color);
543  }
544  province_color.emplace_back((ProvinceId)-2, Eng3D::Color{}); // Water
545  province_color.emplace_back((ProvinceId)-1, Eng3D::Color(0.8f, 0.8f, 0.8f)); // Land
546  return province_color;
547 }
548 
549 std::string language_tooltip(const World& world, const ProvinceId id) {
550  const auto& province = world.provinces[id];
551  if(!province.is_populated()) return "";
552  const auto it = std::max_element(province.languages.begin(), province.languages.end());
553  return world.languages[std::distance(province.languages.begin(), it)].name;
554 }
555 
556 std::vector<ProvinceColor> population_map_mode(const World& world) {
557  // Find the maximum amount of pops in one province
558  std::vector<std::pair<ProvinceId, float>> province_amounts;
559  float max_amount = 1.f;
560  for(auto const& province : world.provinces) {
561  float amount = std::accumulate(province.pops.cbegin(), province.pops.cend(), 0, [](const float a, const auto& e) {
562  return a + e.size;
563  });
564  amount = std::log2(amount);
565  max_amount = glm::max(amount, max_amount);
566  province_amounts.emplace_back(province.get_id(), amount);
567  }
568 
569  // Mix each color depending of how many live there compared to max_amount
570  Eng3D::Color min = Eng3D::Color::rgb8(255, 0, 0);
571  Eng3D::Color max = Eng3D::Color::rgb8(16, 255, 128);
572  std::vector<ProvinceColor> province_color;
573  for(auto const& [province_id, amount] : province_amounts) {
574  if(amount == 0.f)
575  {
576  province_color.emplace_back(province_id, Eng3D::Color::rgb8(255, 255, 255));
577  continue;
578  }
579  auto ratio = amount / max_amount;
580  Eng3D::Color color = Eng3D::Color::lerp(min, max, ratio);
581  province_color.emplace_back(province_id, color);
582  }
583  return province_color;
584 }
585 
586 std::string population_tooltip(const World& world, const ProvinceId id) {
587  const auto& province = world.provinces[id];
588  if(!province.is_populated()) return "";
589  size_t amount = province.total_pops();
590  return string_format("%s\nPopulation: %zu", province.name.c_str(), amount);
591 }
592 
594  return [id](const World& world) {
595  // Find the maximum amount of pops in one province
596  std::vector<std::pair<ProvinceId, float>> province_amounts;
597  auto max_amount = 1.f;
598  for(const auto& province : world.provinces) {
599  auto amount = world.economy_state.trade.get_trade_cost(world.provinces[id], province, glm::vec2{ world.width, world.height });
600  amount = std::log2(amount);
601  max_amount = glm::max(amount, max_amount);
602  province_amounts.emplace_back(province.get_id(), amount);
603  }
604 
605  // Mix each color depending of how many live there compared to max_amount
606  auto min = Eng3D::Color::rgb8(128, 128, 255);
607  auto max = Eng3D::Color::rgb8(255, 64, 64);
608  std::vector<ProvinceColor> province_color;
609  for(const auto& [province_id, amount] : province_amounts) {
610  if(province_id == id)
611  {
612  province_color.emplace_back(province_id, Eng3D::Color::rgb8(255, 255, 128));
613  continue;
614  }
615  auto ratio = amount / max_amount;
616  province_color.emplace_back(province_id, Eng3D::Color::lerp(min, max, ratio));
617  }
618  return province_color;
619  };
620 }
621 
623  return [province_id](const World& world, const ProvinceId id) -> std::string {
624  const auto& province = world.provinces[province_id];
625  const auto& other_province = world.provinces[id];
626  auto amount = world.economy_state.trade.get_trade_cost(province, other_province, glm::vec2{ world.width, world.height });
627  return translate_format("Transport from %s to %s costs %.2f", province.name.c_str(), other_province.name.c_str(), amount);
628  };
629 }
std::vector< AIManager > ai_man
Definition: ai.cpp:55
std::shared_ptr< Eng3D::IO::Asset::Base > get_unique(const Eng3D::IO::Path &path)
Obtaining an unique asset means the "first-found" policy applies.
Definition: io.cpp:146
Eng3D::TextureManager tex_man
Definition: state.hpp:124
Eng3D::IO::PackageManager package_man
Definition: state.hpp:122
std::shared_ptr< Eng3D::Texture > load(const std::string &path, TextureOptions options=default_options)
Finds a texture in the list of a texture manager if the texture is already in the list we load the sa...
Definition: texture.cpp:432
Nation * curr_nation
Definition: game_state.hpp:158
MapMode current_mode
Definition: game_state.hpp:162
std::unique_ptr< Map > map
Definition: game_state.hpp:159
World * world
Definition: game_state.hpp:156
MapmodeCommodityOptions(GameState &gs)
Definition: minimap.cpp:276
Minimap(GameState &gs, int x, int y, UI::Origin origin)
Definition: minimap.cpp:64
Definition: map.hpp:89
void set_map_mode(mapmode_generator mapmode_func, mapmode_tooltip tooltip_func)
Definition: map.cpp:325
A single province, which is used to simulate economy in a "bulk-tiles" way instead of doing economica...
Definition: province.hpp:48
NationId owner_id
Definition: province.hpp:103
Border class that defines the texture and size of borders of the widgets.
Definition: widget.hpp:153
Image widget, can display pictures or effects on the screen.
Definition: image.hpp:43
Simple widget for drawing text on the screen, no multiline support.
Definition: label.hpp:40
The master widget all the other widgets inherit from, do not use directly instead use one of the many...
Definition: widget.hpp:176
UI::Border border
Definition: widget.hpp:334
T & make_widget(Targs &&...args)
Definition: widget.hpp:222
virtual void set_on_click(std::function< void(UI::Widget &)> _on_click)
Sets the on_click function of this widget.
Definition: widget.hpp:259
UI::Origin origin
Definition: widget.hpp:318
bool is_scroll
Definition: widget.hpp:306
std::shared_ptr< Eng3D::Texture > current_texture
Definition: widget.hpp:327
UI::Flex flex
Definition: widget.hpp:337
bool is_pinned
Definition: widget.hpp:302
glm::ivec2 padding
Definition: widget.hpp:323
Definition: world.hpp:114
Nation::Relation & get_relation(NationId a, NationId b)
Definition: world.hpp:192
size_t width
Definition: world.hpp:220
Economy::EconomyState economy_state
Definition: world.hpp:147
size_t height
Definition: world.hpp:220
std::string empty_province_tooltip(const World &, const ProvinceId)
Definition: map.cpp:277
std::string political_province_tooltip(const World &world, const ProvinceId id)
Definition: map.cpp:262
std::vector< ProvinceColor > political_map_mode(const World &world)
Definition: map.cpp:270
std::function< std::string(const World &world, const ProvinceId id)> mapmode_tooltip
Definition: map.hpp:81
std::function< std::vector< ProvinceColor >const World &world)> mapmode_generator
Definition: map.hpp:82
Origin
The origin of the widget.
Definition: widget.hpp:52
@ MIDDLE_RIGHT_SCREEN
mapmode_generator relations_map_mode(NationId id)
Definition: minimap.cpp:412
std::vector< ProvinceColor > language_map_mode(const World &world)
Definition: minimap.cpp:523
const Eng3D::Color MAPMODE_DEFAULT_MAX_COL
Definition: minimap.cpp:45
mapmode_generator trade_map_mode(ProvinceId id)
Definition: minimap.cpp:593
std::vector< ProvinceColor > terrain_map_mode(const World &world)
Definition: minimap.cpp:482
const Eng3D::Color MAPMODE_DEFAULT_MIN_COL
Definition: minimap.cpp:44
std::vector< ProvinceColor > religion_map_mode(const World &world)
Definition: minimap.cpp:491
mapmode_tooltip commodity_tooltip(CommodityId id)
Definition: minimap.cpp:363
mapmode_tooltip relations_tooltip(NationId id)
Definition: minimap.cpp:435
mapmode_generator commodity_map_mode(CommodityId id)
std::string religion_tooltip(const World &world, const ProvinceId id)
Definition: minimap.cpp:517
mapmode_tooltip trade_tooltip(ProvinceId id)
Definition: minimap.cpp:622
std::vector< ProvinceColor > population_map_mode(const World &world)
Definition: minimap.cpp:556
std::string language_tooltip(const World &world, const ProvinceId id)
Definition: minimap.cpp:549
mapmode_generator generic_map_mode(std::function< float(const World &, ProvinceId)> province_value, Eng3D::Color min_col=MAPMODE_DEFAULT_MIN_COL, Eng3D::Color max_col=MAPMODE_DEFAULT_MAX_COL)
Definition: minimap.cpp:385
std::string population_tooltip(const World &world, const ProvinceId id)
Definition: minimap.cpp:586
std::string translate(const std::string_view str)
Definition: string.cpp:76
std::string string_format(const std::string_view format, Args &&... args)
String formatter.
Definition: string.hpp:100
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
Definition: string.hpp:128
float get_trade_cost(const Province &province1, const Province &province2, glm::vec2 world_size) const
Definition: trade.cpp:73
Primitive color type used through the engine.
Definition: color.hpp:32
constexpr static Color rgb8(uint8_t red, uint8_t green, uint8_t blue)
Create a color from RGB components.
Definition: color.hpp:71
constexpr static Color bgr32(uint32_t abgr)
Definition: color.hpp:101
constexpr static Color lerp(Color color1, Color color2, float lamda)
Combine two colors with LERP.
Definition: color.hpp:121
constexpr Id get_id() const
Definition: entity.hpp:152