Symphony Of Empires
unit_widget.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 // eng3d/ui/unit_widget.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include "eng3d/ui/image.hpp"
26 #include "eng3d/ui/label.hpp"
27 #include "eng3d/ui/progress_bar.hpp"
28 #include "eng3d/string.hpp"
29 #include "eng3d/camera.hpp"
30 #include "eng3d/color.hpp"
31 
33 #include "client/map.hpp"
34 #include "client/game_state.hpp"
35 #include "nation.hpp"
36 #include "unit.hpp"
37 #include "world.hpp"
38 
39 using namespace Interface;
40 
42  : UI::Div(0, 0, 100, 30, _parent),
43  map{ _map },
44  gs{ _gs }
45 {
46  this->unit_id = Unit::invalid();
47  this->background_color = Eng3D::Color(1, 1, 1, 1);
48 
49  auto& s = Eng3D::State::get_instance();
50  select_border_texture = s.tex_man.load(s.package_man.get_unique("gfx/border_sharp2.png"));
51  this->border.size = glm::ivec2{this->width, this->height};
52  this->border.texture_size = glm::ivec2{7, 7};
53 
54 #ifndef E3D_HANDHELD
55  this->make_widget<UI::Image>(1, 1, this->width - 1, this->height - 1, "gfx/drop_shadow.png");
56 #endif
57  this->set_on_click([this](UI::Widget&) {
58  if(Unit::is_invalid(this->unit_id)) return;
59  if(gs.client_state.is_selected_unit(this->unit_id)) {
60  gs.client_state.unselect_unit(this->unit_id);
61  } else {
62  gs.client_state.select_unit(this->unit_id);
63  }
64  new Interface::UnitView(this->gs, this->gs.world->unit_manager.units[this->unit_id]);
65  });
66 
67  auto nation_flag = map.nation_flags[0];
68  this->flag_img = new UI::Image(1, 1, 38, 28, nation_flag, this);
69 
70 #ifndef E3D_HANDHELD
71  this->make_widget<UI::Image>(1, 1, 38, 28, "gfx/drop_shadow.png");
72 #endif
73 
74  this->size_label = new UI::Div(41, 1, 48, 28, this);
75  this->size_label->text_align_x = UI::Align::END;
76 
77  this->experience_bar = new UI::ProgressBar(91, 1, 8, 28, 0, 1, this);
78  this->experience_bar->direction = UI::Direction::BOTTOM_TO_TOP;
79 }
80 
81 // This is expected to be called every framed
82 void UnitWidget::set_unit(Unit& _unit) {
83  this->unit_id = _unit.get_id();
84 
85  const auto& camera = *map.camera;
86  auto unit_pos = _unit.get_pos();
87  auto screen_pos = camera.get_tile_screen_pos(unit_pos);
88 
89  this->x = screen_pos.x - this->width / 2;
90  this->y = screen_pos.y - this->height / 2;
91 
92  // If the unit is not selected set give it a border
93  this->border.texture = nullptr;
94  if(!gs.client_state.is_selected_unit(this->unit_id))
95  this->border.texture = this->select_border_texture;
96 
97  // Paint according to relations
98  if(gs.curr_nation != nullptr && _unit.owner_id != gs.curr_nation->get_id()) {
99  const auto& relation = gs.world->get_relation(gs.world->get_id(*gs.curr_nation), _unit.owner_id);
100  if(relation.is_allied()) {
101  this->size_label->background_color = Eng3D::Color::rgba8(0x1e, 0x80, 0x0f, 0x80);
102  } else if(relation.has_war) {
103  this->size_label->background_color = Eng3D::Color::rgba8(0xde, 0x23, 0x23, 0x80);
104  } else {
105  this->size_label->background_color = Eng3D::Color::rgba8(0xff, 0xff, 0xff, 0x80);
106  }
107  } else if(gs.curr_nation != nullptr && _unit.owner_id == gs.curr_nation->get_id()) {
108  this->size_label->background_color = Eng3D::Color::rgba8(0x1e, 0x80, 0x0f, 0x80);
109  }
110 
111  this->flag_img->current_texture = this->gs.get_nation_flag(this->gs.world->nations[_unit.owner_id]);
112  this->set_size(static_cast<size_t>(_unit.size));
113  this->experience_bar->set_value(_unit.experience);
114 }
115 
116 void UnitWidget::set_size(size_t size) {
117  this->size_label->set_text(Eng3D::string_format("%zu", size));
118 }
119 
121  : UI::Window(0, -200, 400, 200),
122  gs{ _gs },
123  unit_id{ _unit.get_id() }
124 {
125  if(this->gs.lower_left_panel != nullptr)
126  this->gs.lower_left_panel->kill();
127  this->gs.lower_left_panel = this;
128  this->set_close_btn_function([this](Widget&) {
129  this->kill();
130  this->gs.lower_left_panel = nullptr;
131  });
132 
134  this->is_scroll = false;
135 
136  auto& unit = this->gs.world->unit_manager.units[this->unit_id];
137  auto& unit_type = this->gs.world->unit_types[unit.type_id];
138  this->set_text(Eng3D::translate_format("Unit %s from %s", unit_type.name.c_str(), this->gs.world->nations[unit.owner_id].name.c_str()));
139 
140  auto& flex_column = this->make_widget<UI::Div>(0, 0, this->width, this->height);
141  flex_column.flex = UI::Flex::COLUMN;
142 
143  auto& target_lab = flex_column.make_widget<UI::Label>(0, 0, " ");
144  target_lab.set_on_each_tick([this](UI::Widget& w) {
145  auto& current_unit = this->gs.world->unit_manager.units[this->unit_id];
146  auto target_id = current_unit.get_target_province_id();
147  if(current_unit.has_target_province()) {
148  const auto& target_province = this->gs.world->provinces[target_id];
149  w.set_text(Eng3D::translate_format("Moving to %s", target_province.name.c_str()));
150  } else {
151  w.set_text(Eng3D::translate_format("No orders"));
152  }
153  });
154  target_lab.on_each_tick(target_lab);
155 
156  auto& size_lab = flex_column.make_widget<UI::Label>(0, 0, " ");
157  size_lab.set_on_each_tick([this](UI::Widget& w) {
158  auto& current_unit = this->gs.world->unit_manager.units[this->unit_id];
159  w.set_text(Eng3D::translate_format("Size: %.2f", current_unit.size));
160  });
161  size_lab.on_each_tick(size_lab);
162 
163  auto& experience_lab = flex_column.make_widget<UI::Label>(0, 0, " ");
164  experience_lab.set_on_each_tick([this](UI::Widget& w) {
165  auto& current_unit = this->gs.world->unit_manager.units[this->unit_id];
166  w.set_text(Eng3D::translate_format("Experience: %.2f", current_unit.experience));
167  });
168  experience_lab.on_each_tick(experience_lab);
169 
170  auto& attdef_lab = flex_column.make_widget<UI::Label>(0, 0, " ");
171  attdef_lab.set_on_each_tick([this](UI::Widget& w) {
172  auto& current_unit = this->gs.world->unit_manager.units[this->unit_id];
173  auto& current_type = this->gs.world->unit_types[current_unit.type_id];
174  w.set_text(Eng3D::translate_format("Attack/Defense: %.2f/%.2f", current_type.attack, current_type.defense));
175  });
176  attdef_lab.on_each_tick(attdef_lab);
177 
178  auto& debug_lab = flex_column.make_widget<UI::Label>(0, 0, " ");
179  debug_lab.set_on_each_tick([this](UI::Widget& w) {
180  auto& current_unit = this->gs.world->unit_manager.units[this->unit_id];
181  auto& current_type = this->gs.world->unit_types[current_unit.type_id];
182  w.set_text(Eng3D::translate_format("On battle?: %s", current_unit.on_battle ? "Yes" : "No"));
183  });
184  debug_lab.on_each_tick(debug_lab);
185 }
bool is_selected_unit(UnitId id) const
Definition: game_state.hpp:64
static State & get_instance()
Definition: state.cpp:514
Nation * curr_nation
Definition: game_state.hpp:158
std::shared_ptr< Eng3D::Texture > get_nation_flag(const Nation &nation)
Definition: game_state.cpp:84
UI::Widget * lower_left_panel
Definition: game_state.hpp:180
ClientState client_state
Definition: game_state.hpp:161
World * world
Definition: game_state.hpp:156
UnitView(GameState &_gs, Unit &unit)
void set_size(size_t size)
UnitWidget(Map &map, GameState &gamestate, UI::Widget *parent)
Definition: unit_widget.cpp:41
void set_unit(Unit &_unit)
Definition: unit_widget.cpp:82
Definition: map.hpp:89
std::unique_ptr< Eng3D::Camera > camera
Definition: map.hpp:151
std::vector< std::shared_ptr< Eng3D::Texture > > nation_flags
Definition: map.hpp:131
glm::ivec2 texture_size
Definition: widget.hpp:157
glm::ivec2 size
Definition: widget.hpp:156
std::shared_ptr< Eng3D::Texture > texture
Definition: widget.hpp:155
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
void set_value(const float _value)
UI::Direction direction
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
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
Eng3D::Color background_color
Definition: widget.hpp:335
bool is_scroll
Definition: widget.hpp:306
size_t width
Definition: widget.hpp:325
UI::Align text_align_x
Definition: widget.hpp:331
std::shared_ptr< Eng3D::Texture > current_texture
Definition: widget.hpp:327
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
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
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
float size
Definition: unit.hpp:132
NationId owner_id
Definition: unit.hpp:128
float experience
Definition: unit.hpp:134
glm::vec2 get_pos() const
Definition: unit.cpp:77
Eng3D::Freelist< Unit > units
Definition: unit.hpp:173
UnitManager unit_manager
Definition: world.hpp:145
Nation::Relation & get_relation(NationId a, NationId b)
Definition: world.hpp:192
T::Id get_id(const T &obj) const
Get the id of an object, this is a template for all types except for tiles and locally-stored types (...
Definition: world.hpp:179
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
Primitive color type used through the engine.
Definition: color.hpp:32
constexpr static Color rgba8(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
Create a color from RGBA components.
Definition: color.hpp:62
constexpr bool is_invalid() const
Checks if the current id is invalid.
Definition: entity.hpp:133
constexpr Id get_id() const
Definition: entity.hpp:152
constexpr static Id invalid()
Returns an invalid id.
Definition: entity.hpp:110
A basic widget without any presets.
Definition: div.hpp:38