Symphony Of Empires
army.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/army.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include "eng3d/string.hpp"
26 #include "eng3d/texture.hpp"
27 #include "eng3d/ui/button.hpp"
28 #include "eng3d/ui/chart.hpp"
29 #include "eng3d/ui/image.hpp"
30 #include "eng3d/ui/label.hpp"
31 #include "eng3d/ui/progress_bar.hpp"
32 #include "eng3d/ui/tooltip.hpp"
33 #include "eng3d/ui/close_button.hpp"
34 #include "eng3d/ui/div.hpp"
35 
37 #include "client/map.hpp"
38 #include "nation.hpp"
39 #include "world.hpp"
40 #include "client/game_state.hpp"
41 
42 using namespace Interface;
43 
44 ArmyUnitsTab::ArmyUnitsTab(GameState& _gs, int _x, int _y, std::function<bool(Unit& unit)> filter, UI::Widget* _parent)
45  : UI::Group(_x, _y, _parent->width - _x, _parent->height - _y, _parent),
46  gs{ _gs }
47 {
48  auto& flex_column = this->make_widget<UI::Div>(0, 0, this->width, this->height);
49  flex_column.flex = UI::Flex::COLUMN;
50  gs.world->unit_manager.units.for_each([&](Unit& unit) {
51  if(!filter || !filter(unit)) return;
52  auto& btn = flex_column.make_widget<UI::Button>(0, 0, this->width, 24);
53  btn.set_on_each_tick([this, unit_id = unit.get_id()](UI::Widget& w) {
54  const auto& current_unit = this->gs.world->unit_manager.units[unit_id];
55  const auto& current_type = this->gs.world->unit_types[current_unit.type_id];
56  w.set_text(string_format("%zu %s", current_unit.size, current_type.name.c_str()));
57  });
58  btn.on_each_tick(btn);
59  });
60 }
61 
63  : UI::Group(_x, _y, _parent->width - _x, _parent->height, _parent),
64  gs{ _gs }
65 {
66  this->is_scroll = true;
67 
68  auto& flex_column = this->make_widget<UI::Div>(0, 0, this->width, this->height);
69  flex_column.flex = UI::Flex::COLUMN;
70  for(const auto& unit_type : gs.world->unit_types) {
71  auto& unit_type_grp = flex_column.make_widget<UI::Div>(0, 0, flex_column.width, 24);
72  unit_type_grp.is_scroll = false;
73  unit_type_grp.flex = UI::Flex::ROW;
74  unit_type_grp.set_on_click([this, unit_type_id = unit_type.get_id()](UI::Widget&) {
75  this->gs.production_queue.push_back(unit_type_id);
76  });
77 
78  auto& icon_img = unit_type_grp.make_widget<UI::Image>(0, 0, 24, 24, unit_type.get_icon_path());
79  auto& name_btn = unit_type_grp.make_widget<UI::Button>(0, 0, unit_type_grp.width - 24, 24);
80  name_btn.right_side_of(icon_img);
81  name_btn.set_text(unit_type.name);
82  }
83 
84  // Chart showing total number of required materials
85  auto& reqmat_chart = flex_column.make_widget<UI::Chart>(0, 0, this->width, 128);
86  reqmat_chart.set_text("Material demand");
87  reqmat_chart.set_on_each_tick([this](UI::Widget& w) {
88  auto& o = static_cast<UI::Chart&>(w);
89  auto total = 0.f;
90  for(const auto province_id : this->gs.curr_nation->owned_provinces) {
91  const auto& province = gs.world->provinces[province_id];
92  for(const auto& building : province.get_buildings()) {
93  for(const auto& [_, amount] : building.req_goods_for_unit)
94  total += amount;
95  for(const auto& [_, amount] : building.req_goods)
96  total += amount;
97  }
98  }
99  //o.data.push_back(total);
100  });
101 
102  for(const auto province_id : gs.curr_nation->owned_provinces)
103  for(const auto& building_type : gs.world->building_types)
104  if(building_type.can_build_land_units())
105  flex_column.make_widget<ArmyProductionUnitInfo>(gs, 0, 0, gs.world->provinces[province_id], building_type);
106 }
107 
108 ArmyProductionUnitInfo::ArmyProductionUnitInfo(GameState& _gs, int _x, int _y, ProvinceId _province_id, size_t _idx, UI::Widget* _parent)
109  : UI::Group(_x, _y, _parent->width - _x, 48, _parent),
110  gs{ _gs },
111  province_id{ _province_id },
112  idx{ _idx }
113 {
114  const auto& province = gs.world->provinces[province_id];
115  const auto& building = province.get_buildings()[idx];
116  this->is_scroll = false;
117  this->flex = UI::Flex::ROW;
119 
120  auto& unit_icon = this->make_widget<UI::Image>(0, 0, 24, 24);
121  unit_icon.current_texture = gs.tex_man.load(gs.package_man.get_unique(gs.world->unit_types[building.working_unit_type_id].get_icon_path()));
122 
123  auto& province_lab = this->make_widget<UI::Label>(0, 0, "?");
124  province_lab.set_on_each_tick([this](UI::Widget& w) {
125  const auto& current_province = gs.world->provinces[province_id];
126  w.set_text(current_province.name);
127  });
128  province_lab.on_each_tick(province_lab);
129 
130  auto& name_lab = this->make_widget<UI::Label>(0, 0, "?");
131  name_lab.set_on_each_tick([this](UI::Widget& w) {
132  const auto& current_province = gs.world->provinces[province_id];
133  auto& current_building = current_province.get_buildings()[this->idx];
134  w.set_text(this->gs.world->unit_types[current_building.working_unit_type_id].name);
135  });
136  name_lab.on_each_tick(name_lab);
137 
138  auto& progress_pgbar = this->make_widget<UI::ProgressBar>(0, 0, 128, 24, 0.f, 1.f);
139  progress_pgbar.set_on_each_tick([this](UI::Widget& _w) {
140  auto& w = static_cast<UI::ProgressBar&>(_w);
141  const auto& c_province = gs.world->provinces[province_id];
142  const auto& c_building = c_province.get_buildings()[this->idx];
143  if(c_building.is_working_on_unit()) return;
144  auto full = 0.f, needed = 0.f;
145  std::string text;
146  for(size_t i = 0; i < c_building.req_goods_for_unit.size(); i++) {
147  auto need_req = c_building.req_goods_for_unit[i];
148  auto full_req = this->gs.world->unit_types[c_building.working_unit_type_id].req_goods[i];
149  full += full_req.second;
150  needed += need_req.second;
151  text += translate_format("Requires %.2f of %s (has %.2f)", need_req.second, this->gs.world->commodities[need_req.first].name.c_str(), full_req.second);
152  }
153  w.set_value(full / glm::max(needed, 0.01f));
154  w.set_tooltip(text);
155  });
156  progress_pgbar.on_each_tick(progress_pgbar);
157 }
158 
160  : UI::Window(-400, 0, 400, _gs.height),
161  gs{ _gs }
162 {
163  if(this->gs.right_side_panel != nullptr)
164  this->gs.right_side_panel->kill();
165  this->gs.right_side_panel = this;
166  this->set_close_btn_function([this](Widget&) {
167  this->kill();
168  this->gs.right_side_panel = nullptr;
169  });
170 
172  this->is_scroll = false;
173  this->set_text(translate("Army management"));
174 
175  this->units_tab = new ArmyUnitsTab(gs, 0, 32, nullptr, this);
176  this->units_tab->is_render = true;
177  auto& army_ibtn = this->make_widget<UI::Image>(0, 0, 32, 32, gs.tex_man.load(gs.package_man.get_unique("gfx/mili&tary_score.png")));
178  army_ibtn.set_on_click([this](UI::Widget&) {
179  this->units_tab->is_render = true;
180  this->units_tab->kill();
181  this->units_tab = &this->make_widget<ArmyUnitsTab>(gs, 0, 32, [this](Unit& unit) {
182  auto& current_type = this->gs.world->unit_types[unit.type_id];
183  return unit.owner_id == *this->gs.curr_nation && current_type.is_ground && !current_type.is_naval;
184  });
185  this->production_tab->is_render = false;
186  });
187  army_ibtn.set_tooltip(translate("Land army"));
188 
189  auto& airforce_ibtn = this->make_widget<UI::Image>(0, 0, 32, 32, gs.tex_man.load(gs.package_man.get_unique("gfx/airforce.png")));
190  airforce_ibtn.right_side_of(army_ibtn);
191  airforce_ibtn.set_on_click([this](UI::Widget&) {
192  this->units_tab->is_render = true;
193  this->units_tab->kill();
194  this->units_tab = &this->make_widget<ArmyUnitsTab>(gs, 0, 32, [this](Unit& unit) {
195  auto& current_type = this->gs.world->unit_types[unit.type_id];
196  return unit.owner_id == *this->gs.curr_nation && !current_type.is_ground && !current_type.is_naval;
197  });
198  this->production_tab->is_render = false;
199  });
200  airforce_ibtn.set_tooltip(translate("Airforce"));
201 
202  auto& navy_ibtn = this->make_widget<UI::Image>(0, 0, 32, 32, gs.tex_man.load(gs.package_man.get_unique("gfx/navy.png")));
203  navy_ibtn.right_side_of(airforce_ibtn);
204  navy_ibtn.set_on_click([this](UI::Widget&) {
205  this->units_tab->is_render = true;
206  this->units_tab->kill();
207  this->units_tab = &this->make_widget<ArmyUnitsTab>(gs, 0, 32, [this](Unit& unit) {
208  auto& current_type = this->gs.world->unit_types[unit.type_id];
209  return unit.owner_id == *this->gs.curr_nation && !current_type.is_ground && current_type.is_naval;
210  });
211  this->production_tab->is_render = false;
212  });
213  navy_ibtn.set_tooltip(translate("Navy"));
214 
215  this->production_tab = new ArmyProductionTab(gs, 0, 32, this);
216  this->production_tab->is_render = true;
217  auto& production_ibtn = this->make_widget<UI::Image>(0, 0, 32, 32, gs.tex_man.load(gs.package_man.get_unique("gfx/production.png")));
218  production_ibtn.right_side_of(navy_ibtn);
219  production_ibtn.set_on_click([this](UI::Widget&) {
220  this->units_tab->is_render = false;
221  this->production_tab->is_render = true;
222  });
223  production_ibtn.set_tooltip(translate("Military production"));
224 
225  army_ibtn.on_click(army_ibtn);
226 }
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
World * world
Definition: game_state.hpp:156
UI::Widget * right_side_panel
Definition: game_state.hpp:179
std::vector< UnitTypeId > production_queue
Definition: game_state.hpp:177
ArmyProductionTab(GameState &gs, int x, int y, UI::Widget *parent)
Definition: army.cpp:62
ArmyProductionUnitInfo(GameState &_gs, int x, int y, ProvinceId _province_id, size_t _idx, UI::Widget *parent)
Definition: army.cpp:108
ArmyUnitsTab(GameState &gs, int x, int y, std::function< bool(Unit &unit)> filter, UI::Widget *parent)
Definition: army.cpp:44
ArmyProductionTab * production_tab
Definition: army.hpp:73
ArmyView(GameState &gs)
Definition: army.cpp:159
ArmyUnitsTab * units_tab
Definition: army.hpp:72
std::vector< ProvinceId > owned_provinces
Definition: nation.hpp:148
Button widget.
Definition: button.hpp:32
A graph chart.
Definition: chart.hpp:40
Image widget, can display pictures or effects on the screen.
Definition: image.hpp:43
The master widget all the other widgets inherit from, do not use directly instead use one of the many...
Definition: widget.hpp:176
T & make_widget(Targs &&...args)
Definition: widget.hpp:222
UI::Overflow overflow
Definition: widget.hpp:340
UI::Origin origin
Definition: widget.hpp:318
virtual void set_tooltip(UI::Tooltip *tooltip)
Set the tooltip to be shown when this widget is hovered, overrides the previous tooltip.
Definition: widget.cpp:458
bool is_scroll
Definition: widget.hpp:306
size_t width
Definition: widget.hpp:325
constexpr void right_side_of(const UI::Widget &rhs)
Definition: widget.hpp:254
virtual void set_on_each_tick(std::function< void(UI::Widget &)> _on_each_tick)
Sets the on_each_tick function of this widget.
Definition: widget.hpp:264
UI::Flex flex
Definition: widget.hpp:337
void kill()
Kills the current widget, setting it up for deletion when dead widgets are cleared by the UI context.
Definition: widget.hpp:283
Widget()=default
virtual void set_text(const std::string &text)
Generates text for the widget and overrides the current text texture.
Definition: widget.cpp:445
size_t height
Definition: widget.hpp:325
bool is_render
Definition: widget.hpp:303
void set_close_btn_function(std::function< void(Widget &)> on_click)
Definition: window.cpp:65
Roughly a batallion, consisting of approximately 500 soldiers each.
Definition: unit.hpp:80
UnitTypeId type_id
Definition: unit.hpp:127
NationId owner_id
Definition: unit.hpp:128
Eng3D::Freelist< Unit > units
Definition: unit.hpp:173
UnitManager unit_manager
Definition: world.hpp:145
@ UPPER_RIGHT_SCREEN
std::string translate(const std::string_view str)
Definition: string.cpp:76
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
Definition: string.hpp:128
void for_each(const F &lambda) const
Definition: freelist.hpp:75
constexpr Id get_id() const
Definition: entity.hpp:152
A basic widget without any presets.
Definition: div.hpp:38