The Battle for Wesnoth  1.17.10+dev
drawer.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2022
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "units/drawer.hpp"
17 
18 #include "color.hpp"
19 #include "display.hpp"
20 #include "display_context.hpp"
21 #include "draw.hpp"
22 #include "formatter.hpp"
23 #include "game_display.hpp"
24 #include "halo.hpp"
25 #include "log.hpp"
26 #include "map/location.hpp"
27 #include "map/map.hpp"
28 #include "picture.hpp"
29 #include "preferences/game.hpp"
30 #include "sdl/surface.hpp"
31 #include "team.hpp"
32 #include "units/animation.hpp"
34 #include "units/frame.hpp"
35 #include "units/types.hpp"
36 #include "units/unit.hpp"
37 
38 static lg::log_domain log_display("display");
39 #define LOG_DP LOG_STREAM(info, log_display)
40 
41 namespace
42 {
43 /**
44  * Wrapper which will assemble the image path (including IPF for the color from get_orb_color) for a given orb.
45  * Returns nullptr if the preferences have been configured to hide this orb.
46  */
47 std::unique_ptr<image::locator> get_orb_image(orb_status os)
48 {
49  if(os == orb_status::disengaged) {
53  return std::make_unique<image::locator>(game_config::images::orb_two_color + "~RC(ellipse_red>"
54  + moved_color + ")~RC(magenta>" + partial_color + ")");
55  }
57  }
58 
60  return nullptr;
61  auto color = orb_status_helper::get_orb_color(os);
62  return std::make_unique<image::locator>(game_config::images::orb + "~RC(magenta>" + color + ")");
63 }
64 
65 void draw_bar(int xpos, int ypos, int bar_height, double filled, const color_t& col)
66 {
67  // Magic width number
68  static constexpr unsigned int bar_width = 4;
69 
70  static constexpr color_t bar_color_bg{0, 0, 0, 80};
71  static constexpr color_t bar_color_border{213, 213, 213, 200};
72 
73  // We used to use an image for the bar instead of drawing it procedurally. Its x,y position
74  // within the file was 19,13, so we offset the origin by that much to make it line up with
75  // the crowns as before. Should probably compensate for this better in the future.
76  const point offset = display::scaled_to_zoom(point{19, 13});
77 
78  // Full bar dimensions.
79  const rect bar_rect = display::scaled_to_zoom({
80  xpos + offset.x,
81  ypos + offset.y,
82  bar_width,
83  bar_height
84  });
85 
86  filled = std::clamp<double>(filled, 0.0, 1.0);
87  const int unfilled = static_cast<std::size_t>(bar_rect.h * (1.0 - filled));
88 
89  // Filled area dimensions.
90  const rect fill_rect {
91  bar_rect.x,
92  bar_rect.y + unfilled,
93  bar_rect.w,
94  bar_rect.h - unfilled
95  };
96 
97  // Tinted background.
98  draw::fill(bar_rect, bar_color_bg);
99 
100  // Filled area.
101  draw::fill(fill_rect, col);
102 
103  // Bar outline.
104  draw::rect(bar_rect, bar_color_border);
105 }
106 }
107 
109  : disp(thedisp)
110  , dc(disp.get_disp_context())
111  , map(dc.map())
112  , teams(dc.teams())
113  , halo_man(thedisp.get_halo_manager())
114  , viewing_team(disp.viewing_team())
115  , playing_team(disp.playing_team())
116  , viewing_team_ref(teams[viewing_team])
117  , playing_team_ref(teams[playing_team])
118  , is_blindfolded(disp.is_blindfolded())
119  , show_everything(disp.show_everything())
120  , sel_hex(disp.selected_hex())
121  , mouse_hex(disp.mouseover_hex())
122  , zoom_factor(disp.get_zoom_factor())
123  , hex_size(disp.hex_size())
124  , hex_size_by_2(disp.hex_size() / 2)
125 {
126  if(const game_display* game_display = dynamic_cast<class game_display*>(&disp)) {
128  }
129 
130  // This used to be checked in the drawing code, where it simply triggered skipping some logic.
131  // However, I think it's obsolete, and that the initialization of viewing_team_ref would already
132  // be undefined behavior in the situation where this assert fails.
133  assert(disp.team_valid());
134 }
135 
136 void unit_drawer::redraw_unit(const unit& u) const
137 {
139  map_location loc = u.get_location();
140 
141  int side = u.side();
142 
143  bool hidden = u.get_hidden();
144  bool is_flying = u.is_flying();
145  map_location::DIRECTION facing = u.facing();
146  int hitpoints = u.hitpoints();
147  int max_hitpoints = u.max_hitpoints();
148 
149  bool can_recruit = u.can_recruit();
150  bool can_advance = u.can_advance();
151 
152  int experience = u.experience();
153  int max_experience = u.max_experience();
154 
155  bool emit_zoc = u.emits_zoc();
156 
157  color_t hp_color=u.hp_color();
158  color_t xp_color=u.xp_color();
159 
160  std::string ellipse=u.image_ellipse();
161 
162  const bool is_highlighted_enemy = units_that_can_reach_goal.count(loc) > 0;
163  const bool is_selected_hex = (loc == sel_hex || is_highlighted_enemy);
164 
165  // Override the filled area's color's alpha.
166  hp_color.a = (loc == mouse_hex || is_selected_hex) ? 255u : float_to_color(0.8);
167  xp_color.a = hp_color.a;
168 
170  ac.clear_haloes();
171  if(ac.anim_) {
172  ac.anim_->update_last_draw_time();
173  }
174  return;
175  }
176 
177  if (!ac.anim_) {
178  ac.set_standing();
179  if (!ac.anim_) return;
180  }
181 
182  if (ac.refreshing_) return;
183  ac.refreshing_ = true;
184 
185  ac.anim_->update_last_draw_time();
186  frame_parameters params;
187  const t_translation::terrain_code terrain = map.get_terrain(loc);
188  const terrain_type& terrain_info = map.get_terrain_info(terrain);
189 
190  // do not set to 0 so we can distinguish the flying from the "not on submerge terrain"
191  // instead use -1.0 (as in "negative depth", it will be ignored by rendering)
192  params.submerge= is_flying ? -1.0 : terrain_info.unit_submerge();
193 
194  if(u.invisible(loc) && params.highlight_ratio > 0.6) {
195  params.highlight_ratio = 0.6;
196  }
197  if (is_selected_hex && params.highlight_ratio == 1.0) {
198  params.highlight_ratio = 1.5;
199  }
200 
201  int height_adjust = static_cast<int>(terrain_info.unit_height_adjust() * zoom_factor);
202  if (is_flying && height_adjust < 0) {
203  height_adjust = 0;
204  }
205  params.y -= height_adjust;
206  params.halo_y -= height_adjust;
207 
208  int red = 0,green = 0,blue = 0,tints = 0;
209  double blend_ratio = 0;
210  // Add future colored states here
211  if(u.poisoned()) {
212  green += 255;
213  blend_ratio += 0.25;
214  tints += 1;
215  }
216  if(u.slowed()) {
217  red += 191;
218  green += 191;
219  blue += 255;
220  blend_ratio += 0.25;
221  tints += 1;
222  }
223  if(tints > 0) {
224  params.blend_with = color_t((red/tints),(green/tints),(blue/tints));
225  params.blend_ratio = ((blend_ratio/tints));
226  }
227 
228  //hackish : see unit_frame::merge_parameters
229  // we use image_mod on the primary image
230  // and halo_mod on secondary images and all haloes
231  params.image_mod = u.image_mods();
232  params.halo_mod = u.TC_image_mods();
233  params.image= u.default_anim_image();
234 
235 
236  if(u.incapacitated()) params.image_mod +="~GS()";
237  params.primary_frame = true;
238 
239 
240  const frame_parameters adjusted_params = ac.anim_->get_current_params(params);
241 
242  const map_location dst = loc.get_direction(facing);
243  const int xsrc = disp.get_location_x(loc);
244  const int ysrc = disp.get_location_y(loc);
245  const int xdst = disp.get_location_x(dst);
246  const int ydst = disp.get_location_y(dst);
247 
248  // We draw bars only if wanted, visible on the map view
249  bool draw_bars = ac.draw_bars_ ;
250  if (draw_bars) {
251  rect unit_rect {xsrc, ysrc +adjusted_params.y, hex_size, hex_size};
252  draw_bars = unit_rect.overlaps(disp.map_outside_area());
253  }
254 
255  texture ellipse_front;
256  texture ellipse_back;
257  int ellipse_floating = 0;
258  // Always show the ellipse for selected units
259  if(draw_bars && (preferences::show_side_colors() || is_selected_hex)) {
260  if(adjusted_params.submerge > 0.0) {
261  // The division by 2 seems to have no real meaning,
262  // It just works fine with the current center of ellipse
263  // and prevent a too large adjust if submerge = 1.0
264  ellipse_floating = static_cast<int>(adjusted_params.submerge * hex_size_by_2);
265  }
266 
267  if(ellipse.empty()){
268  ellipse="misc/ellipse";
269  }
270 
271  if(ellipse != "none") {
272  // check if the unit has a ZoC or can recruit
273  const std::string nozoc = !emit_zoc ? "nozoc-" : "";
274  const std::string leader = can_recruit ? "leader-" : "";
275  const std::string selected = is_selected_hex? "selected-" : "";
276  const std::string tc = team::get_side_color_id(side);
277 
278  const std::string ellipse_top = formatter() << ellipse << "-" << leader << nozoc << selected << "top.png~RC(ellipse_red>" << tc << ")";
279  const std::string ellipse_bot = formatter() << ellipse << "-" << leader << nozoc << selected << "bottom.png~RC(ellipse_red>" << tc << ")";
280 
281  // Load the ellipse parts recolored to match team color
282  ellipse_back = image::get_texture(image::locator(ellipse_top));
283  ellipse_front = image::get_texture(image::locator(ellipse_bot));
284  }
285  }
286 
287  disp.drawing_buffer_add(display::LAYER_UNIT_FIRST, loc, [=, adj_y = adjusted_params.y](const rect& d) {
288  // Both front and back have the same origin
289  const point origin { d.x, d.y + adj_y - ellipse_floating };
290 
291  if(ellipse_back) {
292  draw::blit(ellipse_back, display::scaled_to_zoom({origin.x, origin.y, ellipse_back.w(), ellipse_back.h()}));
293  }
294 
295  if(ellipse_front) {
296  draw::blit(ellipse_front, display::scaled_to_zoom({origin.x, origin.y, ellipse_front.w(), ellipse_front.h()}));
297  }
298  });
299 
300  if(draw_bars) {
301  const auto& type_cfg = u.type().get_cfg();
302  const auto& cfg_offset_x = type_cfg["bar_offset_x"];
303  const auto& cfg_offset_y = type_cfg["bar_offset_y"];
304  int xoff;
305  int yoff;
306  if(cfg_offset_x.empty() && cfg_offset_y.empty()) {
308  image::get_size(u.default_anim_image())
309  );
310  xoff = !s.x ? 0 : (hex_size - s.x)/2;
311  yoff = !s.y ? 0 : (hex_size - s.x)/2;
312  }
313  else {
314  xoff = cfg_offset_x.to_int();
315  yoff = cfg_offset_y.to_int();
316  }
317 
318  using namespace orb_status_helper;
319  std::unique_ptr<image::locator> orb_img = nullptr;
320 
321  if(viewing_team_ref.is_enemy(side)) {
322  if(!u.incapacitated())
323  orb_img = get_orb_image(orb_status::enemy);
324  } else if(static_cast<std::size_t>(side) != playing_team + 1) {
325  // We're looking at either the player's own unit or an ally's unit, but either way it
326  // doesn't belong to the playing_team and isn't expected to move until after its next
327  // turn refresh.
328  auto os = orb_status::moved;
329  if(static_cast<std::size_t>(side) != viewing_team + 1)
330  os = orb_status::allied;
331  orb_img = get_orb_image(os);
332  } else {
333  // We're looking at either the player's own unit, or an ally's unit, during the unit's
334  // owner's turn.
335  auto os = dc.unit_orb_status(u);
336  orb_img = get_orb_image(os);
337  }
338 
339  // All the various overlay textures to draw with the HP/XP bars
340  std::vector<texture> textures;
341 
342  if(orb_img != nullptr) {
343  textures.push_back(image::get_texture(*orb_img));
344  }
345 
346  if(can_recruit) {
347  if(texture tex = image::get_texture(u.leader_crown())) {
348  textures.push_back(std::move(tex));
349  }
350  }
351 
352  for(const std::string& ov : u.overlays()) {
353  if(texture tex = image::get_texture(ov)) {
354  textures.push_back(std::move(tex));
355  }
356  };
357 
359  textures = std::move(textures),
360  adj_y = adjusted_params.y,
361  //origin = point{xsrc + xoff, ysrc + yoff + adjusted_params.y},
362  bar_hp_height = static_cast<int>(max_hitpoints * u.hp_bar_scaling()),
363  bar_xp_height = static_cast<int>(max_experience * u.xp_bar_scaling() / std::max<int>(u.level(), 1))
364  ](const rect& d) {
365  const point origin { d.x + xoff, d.y + yoff + adj_y };
366 
367  for(const texture& tex : textures) {
368  draw::blit(tex, display::scaled_to_zoom({origin.x, origin.y, tex.w(), tex.h()}));
369  }
370 
371  if(max_hitpoints > 0) {
372  // Offset slightly to make room for the XP bar
373  const int hp_offset = static_cast<int>(-5 * display::get_zoom_factor());
374 
375  double filled = static_cast<double>(hitpoints) / static_cast<double>(max_hitpoints);
376  draw_bar(origin.x + hp_offset, origin.y, bar_hp_height, filled, hp_color);
377  }
378 
379  if(experience > 0 && can_advance) {
380  double filled = static_cast<double>(experience) / static_cast<double>(max_experience);
381  draw_bar(origin.x, origin.y, bar_xp_height, filled, xp_color);
382  }
383  });
384  }
385 
386  // Smooth unit movements from terrain of different elevation.
387  // Do this separately from above so that the health bar doesn't go up and down.
388 
389  const t_translation::terrain_code terrain_dst = map.get_terrain(dst);
390  const terrain_type& terrain_dst_info = map.get_terrain_info(terrain_dst);
391 
392  // height_adjust_unit is not scaled by zoom_factor here otherwise it results in a squared offset that results in #5974
393  // It appears the tiles and units are scaled together somewhere else
394  int height_adjust_unit = static_cast<int>(terrain_info.unit_height_adjust() * (1.0 - adjusted_params.offset) +
395  terrain_dst_info.unit_height_adjust() * adjusted_params.offset);
396  if (is_flying && height_adjust_unit < 0) {
397  height_adjust_unit = 0;
398  }
399  params.y -= height_adjust_unit - height_adjust;
400  params.halo_y -= height_adjust_unit - height_adjust;
401  // TODO: params.halo_y is not used. Why is it set?
402 
403  const int halo_x =
404  static_cast<int>(
405  adjusted_params.offset * xdst
406  + (1.0 - adjusted_params.offset) * xsrc
407  )
408  + hex_size_by_2;
409  const int halo_y =
410  static_cast<int>(
411  adjusted_params.offset * ydst
412  + (1.0 - adjusted_params.offset) * ysrc
413  )
414  + hex_size_by_2 - height_adjust_unit * zoom_factor;
415 
416  bool has_halo = ac.unit_halo_ && ac.unit_halo_->valid();
417  if(!has_halo && !u.image_halo().empty()) {
418  ac.unit_halo_ = halo_man.add(
419  halo_x, halo_y,
420  u.image_halo() + u.TC_image_mods(),
421  map_location(-1, -1)
422  );
423  }
424  if(has_halo && u.image_halo().empty()) {
425  halo_man.remove(ac.unit_halo_);
426  ac.unit_halo_.reset();
427  } else if(has_halo) {
428  halo_man.set_location(ac.unit_halo_, halo_x, halo_y);
429  }
430 
431  ac.anim_->redraw(params, halo_man);
432  ac.refreshing_ = false;
433 }
Drawing functions, for drawing things on the screen.
bool refreshing_
avoid infinite recursion.
Reserve layers to be selected for WML.
Definition: display.hpp:801
All parameters from a frame at a given instant.
Definition: frame.hpp:35
image::locator image
Definition: frame.hpp:41
bool is_blindfolded
Definition: drawer.hpp:61
std::optional< color_t > blend_with
Definition: frame.hpp:55
This class represents a single unit of a specific type.
Definition: unit.hpp:133
static rect scaled_to_zoom(const SDL_Rect &r)
Scale the width and height of a rect by the current zoom factor.
Definition: display.hpp:262
bool is_flying() const
Check if the unit is a flying unit.
Definition: unit.hpp:1467
static double get_zoom_factor()
Returns the current zoom factor.
Definition: display.hpp:256
const std::set< map_location > & units_that_can_reach_goal() const
Return the locations of units that can reach goal (.
std::unique_ptr< unit_animation > anim_
The current animation.
double unit_submerge() const
Definition: terrain.hpp:138
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:502
Frame for unit&#39;s animation sequence.
constexpr uint8_t float_to_color(double n)
Convert a double in the range [0.0,1.0] to an 8-bit colour value.
Definition: color.hpp:280
int hex_size
Definition: drawer.hpp:68
halo::manager & halo_man
Definition: drawer.hpp:56
static lg::log_domain log_display("display")
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:98
map_location::DIRECTION facing() const
The current direction this unit is facing within its hex.
Definition: unit.hpp:1374
bool draw_bars_
bool indicating whether to draw bars with the unit
#define d
Belongs to a friendly side.
std::string image_ellipse() const
Get the unit&#39;s ellipse image.
Definition: unit.hpp:1566
bool show_side_colors()
Definition: game.cpp:747
point get_size(const locator &i_locator, bool skip_cache)
Returns the width and height of an image.
Definition: picture.cpp:970
orb_status
Corresponds to the colored orbs displayed above units&#39; hp-bar and xp-bar.
Definition: orb_status.hpp:24
bool get_hidden() const
Gets whether this unit is currently hidden on the map.
Definition: unit.hpp:723
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:32
void rect(const SDL_Rect &rect)
Draw a rectangle.
Definition: draw.cpp:141
map_location get_direction(DIRECTION dir, unsigned int n=1u) const
Definition: location.cpp:360
bool team_valid() const
Definition: display.cpp:716
color_t hp_color() const
Color for this unit&#39;s current hitpoints.
Definition: unit.cpp:1087
bool poisoned() const
Check if the unit has been poisoned.
Definition: unit.hpp:897
Belongs to a non-friendly side; normally visualised by not displaying an orb.
void clear_haloes()
Clear the haloes associated to the unit.
int unit_height_adjust() const
Definition: terrain.hpp:137
void drawing_buffer_add(const drawing_layer layer, const map_location &loc, decltype(draw_helper::do_draw) draw_func)
Add an item to the drawing buffer.
Definition: display.cpp:1278
std::string halo_mod
Definition: frame.hpp:50
std::ostringstream wrapper.
Definition: formatter.hpp:39
std::string get_orb_color(orb_status os)
Wrapper for the various preferences::unmoved_color(), moved_color(), etc methods, using the enum inst...
Definition: orb_status.cpp:40
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:302
color_t xp_color() const
Color for this unit&#39;s XP.
Definition: unit.cpp:1141
Unit bars and overlays are drawn on this layer (for testing here).
Definition: display.hpp:826
std::string selected
int hex_size_by_2
Definition: drawer.hpp:69
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:58
const gamemap & map
Definition: drawer.hpp:54
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:532
bool is_enemy(int n) const
Definition: team.hpp:231
map_display and display: classes which take care of displaying the map and game-data on the screen...
display & disp
Definition: drawer.hpp:52
std::string default_anim_image() const
The default image to use for animation frames with no defined image.
Definition: unit.cpp:2419
std::set< map_location > units_that_can_reach_goal
Definition: drawer.hpp:66
Generic locator abstracting the location of an image.
Definition: picture.hpp:62
static std::string get_side_color_id(unsigned side)
Definition: team.cpp:969
handle add(int x, int y, const std::string &image, const map_location &loc, halo::ORIENTATION orientation=NORMAL, bool infinite=true)
Add a haloing effect using &#39;image centered on (x,y).
Definition: halo.cpp:426
Encapsulates the map of the game.
Definition: location.hpp:38
bool invisible(const map_location &loc, bool see_all=true) const
Definition: unit.cpp:2437
double highlight_ratio
Definition: frame.hpp:58
unit_animation_component & anim_comp() const
Definition: unit.hpp:1545
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:508
std::string moved_color()
Definition: general.cpp:345
static map_location::DIRECTION s
std::string image_mod
Definition: frame.hpp:44
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:615
int get_location_y(const map_location &loc) const
Definition: display.cpp:736
const team & viewing_team_ref
Definition: drawer.hpp:59
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:46
Holds a 2D point.
Definition: point.hpp:24
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
const display_context & dc
Definition: drawer.hpp:53
All moves and possible attacks have been done.
std::size_t viewing_team
Definition: drawer.hpp:57
void set_location(const handle &h, int x, int y)
Set the position of an existing haloing effect, according to its handle.
Definition: halo.cpp:434
void blit(const texture &tex, const SDL_Rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition: draw.cpp:301
bool is_visible_to_team(const team &team, bool const see_all=true) const
Definition: unit.cpp:2480
double blend_ratio
Definition: frame.hpp:57
double submerge
Definition: frame.hpp:60
std::string partial_color()
Definition: general.cpp:365
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:731
void redraw_unit(const unit &u) const
draw a unit.
Definition: drawer.cpp:136
unit_drawer(display &thedisp)
Definition: drawer.cpp:108
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:526
orb_status unit_orb_status(const unit &u) const
Returns an enumurated summary of whether this unit can move and/or attack.
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1358
Standard logging facilities (interface).
bool can_advance() const
Checks whether this unit has any options to advance to.
Definition: unit.hpp:275
bool incapacitated() const
Check if the unit has been petrified.
Definition: unit.hpp:906
The unit can move but can&#39;t attack, and wouldn&#39;t be able to attack even if it was moved to a hex adja...
rect map_outside_area() const
Returns the available area for a map, this may differ from the above.
Definition: display.cpp:564
bool emits_zoc() const
Tests whether the unit has a zone-of-control, considering incapacitated.
Definition: unit.hpp:1339
int side() const
The side this unit belongs to.
Definition: unit.hpp:346
bool prefs_show_orb(orb_status os)
Wrapper for the various preferences::show_..._orb() methods, using the enum instead of exposing a sep...
Definition: orb_status.cpp:19
void set_standing(bool with_bars=true)
Sets the animation state to standing.
std::size_t playing_team
Definition: drawer.hpp:58
There are still moves and/or attacks possible, but the unit doesn&#39;t fit in the "unmoved" status...
std::string orb_two_color
bool slowed() const
Check if the unit has been slowed.
Definition: unit.hpp:915
texture get_texture(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image texture suitable for hardware-accelerated rendering.
Definition: picture.cpp:1128
double zoom_factor
Definition: drawer.hpp:65
bool show_everything
Definition: drawer.hpp:62
std::string TC_image_mods() const
Constructs a recolor (RC) IPF string for this unit&#39;s team color.
Definition: unit.cpp:2590
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:41
boost::tribool primary_frame
Definition: frame.hpp:69
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition: unit.cpp:2595
map_location mouse_hex
Definition: drawer.hpp:64
void remove(const handle &h)
Remove the halo with the given handle.
Definition: halo.cpp:440
map_location sel_hex
Definition: drawer.hpp:63