The Battle for Wesnoth  1.19.24+dev
frame.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2025
3  by Jeremy Rosen <jeremy.rosen@enst-bretagne.fr>
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/frame.hpp"
17 
18 #include "color.hpp"
19 #include "draw.hpp"
20 #include "game_display.hpp"
21 #include "log.hpp"
22 #include "serialization/chrono.hpp"
23 #include "sound.hpp"
24 
25 static lg::log_domain log_engine("engine");
26 #define ERR_NG LOG_STREAM(err, log_engine)
27 
29  : duration_(1)
30  , auto_vflip_(boost::logic::indeterminate)
31  , auto_hflip_(boost::logic::indeterminate)
32  , primary_frame_(boost::logic::indeterminate)
34 {}
35 
36 frame_builder::frame_builder(const config& cfg,const std::string& frame_string)
37  : duration_(1)
38  , image_(cfg[frame_string + "image"])
39  , image_diagonal_(cfg[frame_string + "image_diagonal"])
40  , image_mod_(cfg[frame_string + "image_mod"])
41  , halo_(cfg[frame_string + "halo"])
42  , halo_x_(cfg[frame_string + "halo_x"])
43  , halo_y_(cfg[frame_string + "halo_y"])
44  , halo_mod_(cfg[frame_string + "halo_mod"])
45  , sound_(cfg[frame_string + "sound"])
46  , text_(cfg[frame_string + "text"])
47  , blend_ratio_(cfg[frame_string + "blend_ratio"])
48  , highlight_ratio_(cfg[frame_string + "alpha"])
49  , offset_(cfg[frame_string + "offset"])
50  , submerge_(cfg[frame_string + "submerge"])
51  , x_(cfg[frame_string + "x"])
52  , y_(cfg[frame_string + "y"])
53  , directional_x_(cfg[frame_string + "directional_x"])
54  , directional_y_(cfg[frame_string + "directional_y"])
55  , auto_vflip_(boost::logic::indeterminate)
56  , auto_hflip_(boost::logic::indeterminate)
57  , primary_frame_(boost::logic::indeterminate)
58  , drawing_layer_(cfg[frame_string + "layer"])
59 {
60  if(cfg.has_attribute(frame_string + "auto_vflip")) {
61  auto_vflip_ = cfg[frame_string + "auto_vflip"].to_bool();
62  }
63 
64  if(cfg.has_attribute(frame_string + "auto_hflip")) {
65  auto_hflip_ = cfg[frame_string + "auto_hflip"].to_bool();
66  }
67 
68  if(cfg.has_attribute(frame_string + "primary")) {
69  primary_frame_ = cfg[frame_string + "primary"].to_bool();
70  }
71 
72  const auto& text_color_key = cfg[frame_string + "text_color"];
73  if(!text_color_key.empty()) {
74  try {
75  text_color_ = color_t::from_rgb_string(text_color_key.str());
76  } catch(const std::invalid_argument& e) {
77  // Might be thrown either due to an incorrect number of elements or std::stoul failure.
78  ERR_NG << "Invalid RBG text color in unit animation: " << text_color_key.str()
79  << "\n" << e.what();
80  }
81  }
82 
83  if(const config::attribute_value* v = cfg.get(frame_string + "duration")) {
84  duration(chrono::parse_duration<std::chrono::milliseconds>(*v));
85  } else if(!cfg.get(frame_string + "end")) {
86  auto halo_duration = progressive_string(halo_, 1ms).duration();
87  auto image_duration = progressive_image(image_, 1ms).duration();
88  auto image_diagonal_duration = progressive_image(image_diagonal_, 1ms).duration();
89 
90  duration(std::max(std::max(image_duration, image_diagonal_duration), halo_duration));
91  } else {
92  auto t1 = chrono::parse_duration<std::chrono::milliseconds>(cfg[frame_string + "begin"]);
93  auto t2 = chrono::parse_duration<std::chrono::milliseconds>(cfg[frame_string + "end"]);
94  duration(t2 - t1);
95  }
96 
97  duration_ = std::max(duration_, 1ms);
98 
99  const auto& blend_color_key = cfg[frame_string + "blend_color"];
100  if(!blend_color_key.empty()) {
101  try {
102  blend_with_ = color_t::from_rgb_string(blend_color_key.str());
103  } catch(const std::invalid_argument& e) {
104  // Might be thrown either due to an incorrect number of elements or std::stoul failure.
105  ERR_NG << "Invalid RBG blend color in unit animation: " << blend_color_key.str()
106  << "\n" << e.what();
107  }
108  }
109 }
110 
111 frame_builder& frame_builder::image(const std::string& image ,const std::string& image_mod)
112 {
113  image_ = image;
114  image_mod_ = image_mod;
115  return *this;
116 }
117 
118 frame_builder& frame_builder::image_diagonal(const std::string& image_diagonal,const std::string& image_mod)
119 {
121  image_mod_ = image_mod;
122  return *this;
123 }
124 
126 {
127  sound_ = sound;
128  return *this;
129 }
130 
131 frame_builder& frame_builder::text(const std::string& text,const color_t text_color)
132 {
133  text_ = text;
134  text_color_ = text_color;
135  return *this;
136 }
137 
138 frame_builder& frame_builder::halo(const std::string& halo, const std::string& halo_x, const std::string& halo_y,const std::string& halo_mod)
139 {
140  halo_ = halo;
141  halo_x_ = halo_x;
142  halo_y_ = halo_y;
143  halo_mod_= halo_mod;
144  return *this;
145 }
146 
147 frame_builder& frame_builder::duration(const std::chrono::milliseconds& duration)
148 {
150  return *this;
151 }
152 
153 frame_builder& frame_builder::blend(const std::string& blend_ratio,const color_t blend_color)
154 {
155  blend_with_ = blend_color;
156  blend_ratio_ = blend_ratio;
157  return *this;
158 }
159 
160 frame_builder& frame_builder::highlight(const std::string& highlight)
161 {
163  return *this;
164 }
165 
166 frame_builder& frame_builder::offset(const std::string& offset)
167 {
168  offset_ = offset;
169  return *this;
170 }
171 
172 frame_builder& frame_builder::submerge(const std::string& submerge)
173 {
175  return *this;
176 }
177 
178 frame_builder& frame_builder::x(const std::string& x)
179 {
180  x_ = x;
181  return *this;
182 }
183 
184 frame_builder& frame_builder::y(const std::string& y)
185 {
186  y_ = y;
187  return *this;
188 }
189 
190 frame_builder& frame_builder::directional_x(const std::string& directional_x)
191 {
193  return *this;
194 }
195 
196 frame_builder& frame_builder::directional_y(const std::string& directional_y)
197 {
199  return *this;
200 }
201 
203 {
205  return *this;
206 }
207 
209 {
211  return *this;
212 }
213 
214 frame_builder& frame_builder::primary_frame(const bool primary_frame)
215 {
217  return *this;
218 }
219 
221 {
223  return *this;
224 }
225 
226 frame_parsed_parameters::frame_parsed_parameters(const frame_builder& builder, const std::chrono::milliseconds& duration)
227  : duration_(duration > std::chrono::milliseconds{0} ? duration : builder.duration_)
228  , image_(builder.image_,duration_)
229  , image_diagonal_(builder.image_diagonal_,duration_)
230  , image_mod_(builder.image_mod_)
231  , halo_(builder.halo_,duration_)
232  , halo_x_(builder.halo_x_,duration_)
233  , halo_y_(builder.halo_y_,duration_)
234  , halo_mod_(builder.halo_mod_)
235  , sound_(builder.sound_)
236  , text_(builder.text_)
237  , text_color_(builder.text_color_)
238  , blend_with_(builder.blend_with_)
239  , blend_ratio_(builder.blend_ratio_,duration_)
240  , highlight_ratio_(builder.highlight_ratio_,duration_)
241  , offset_(builder.offset_,duration_)
242  , submerge_(builder.submerge_,duration_)
243  , x_(builder.x_,duration_)
244  , y_(builder.y_,duration_)
245  , directional_x_(builder.directional_x_,duration_)
246  , directional_y_(builder.directional_y_,duration_)
247  , auto_vflip_(builder.auto_vflip_)
248  , auto_hflip_(builder.auto_hflip_)
249  , primary_frame_(builder.primary_frame_)
250  , drawing_layer_(builder.drawing_layer_,duration_)
251 {}
252 
254 {
255  return
265  x_.does_not_change() &&
266  y_.does_not_change() &&
270 }
271 
273 {
274  return !this->does_not_change();
275 }
276 
277 frame_parameters frame_parsed_parameters::parameters(const std::chrono::milliseconds& current_time) const
278 {
279 #ifdef __cpp_designated_initializers
280  return {
281  .duration = duration_,
282  .image = image_.get_current_element(current_time),
283  .image_diagonal = image_diagonal_.get_current_element(current_time),
284  .image_mod = image_mod_,
285  .halo = halo_.get_current_element(current_time),
286  .halo_x = halo_x_.get_current_element(current_time),
287  .halo_y = halo_y_.get_current_element(current_time),
288  .halo_mod = halo_mod_,
289  .sound = sound_,
290  .text = text_,
291  .text_color = text_color_,
292  .blend_with = blend_with_,
293  .blend_ratio = blend_ratio_.get_current_element(current_time),
294  .highlight_ratio = highlight_ratio_.get_current_element(current_time,1.0),
295  .offset = offset_.get_current_element(current_time,-1000),
296  .submerge = submerge_.get_current_element(current_time),
297  .x = x_.get_current_element(current_time),
298  .y = y_.get_current_element(current_time),
299  .directional_x = directional_x_.get_current_element(current_time),
300  .directional_y = directional_y_.get_current_element(current_time),
301  .auto_vflip = auto_vflip_,
302  .auto_hflip = auto_hflip_,
303  .primary_frame = primary_frame_,
305  };
306 #else
307  frame_parameters result;
308  result.duration = duration_;
309  result.image = image_.get_current_element(current_time);
310  result.image_diagonal = image_diagonal_.get_current_element(current_time);
311  result.image_mod = image_mod_;
312  result.halo = halo_.get_current_element(current_time);
313  result.halo_x = halo_x_.get_current_element(current_time);
314  result.halo_y = halo_y_.get_current_element(current_time);
315  result.halo_mod = halo_mod_;
316  result.sound = sound_;
317  result.text = text_;
318  result.text_color = text_color_;
319  result.blend_with = blend_with_;
320  result.blend_ratio = blend_ratio_.get_current_element(current_time);
321  result.highlight_ratio = highlight_ratio_.get_current_element(current_time,1.0);
322  result.offset = offset_.get_current_element(current_time,-1000);
323  result.submerge = submerge_.get_current_element(current_time);
324  result.x = x_.get_current_element(current_time);
325  result.y = y_.get_current_element(current_time);
326  result.directional_x = directional_x_.get_current_element(current_time);
327  result.directional_y = directional_y_.get_current_element(current_time);
328  result.auto_vflip = auto_vflip_;
329  result.auto_hflip = auto_hflip_;
330  result.primary_frame = primary_frame_;
332  return result;
333 #endif
334 }
335 
336 void frame_parsed_parameters::override(const std::chrono::milliseconds& duration,
337  const std::string& highlight,
338  const std::string& blend_ratio,
339  color_t blend_color,
340  const std::string& offset,
341  const std::string& layer,
342  const std::string& modifiers)
343 {
344  if(!highlight.empty()) {
346  } else if(duration != duration_){
348  }
349 
350  if(!offset.empty()) {
352  } else if(duration != duration_){
354  }
355 
356  if(!blend_ratio.empty()) {
358  blend_with_ = blend_color;
359  } else if(duration != duration_){
361  }
362 
363  if(!layer.empty()) {
365  } else if(duration != duration_){
367  }
368 
369  if(!modifiers.empty()) {
370  image_mod_ += modifiers;
371  }
372 
373  if(duration != duration_) {
385  }
386 }
387 
388 std::vector<std::string> frame_parsed_parameters::debug_strings() const
389 {
390  std::vector<std::string> v;
391 
392  if(duration_ > 0ms) {
393  v.emplace_back("duration=" + utils::half_signed_value(duration_.count()));
394  }
395 
396  if(!image_.get_original().empty()) {
397  v.emplace_back("image=" + image_.get_original());
398  }
399 
400  if(!image_diagonal_.get_original().empty()) {
401  v.emplace_back("image_diagonal=" + image_diagonal_.get_original());
402  }
403 
404  if(!image_mod_.empty()) {
405  v.emplace_back("image_mod=" + image_mod_);
406  }
407 
408  if(!halo_.get_original().empty()) {
409  v.emplace_back("halo=" + halo_.get_original());
410  }
411 
412  if(!halo_x_.get_original().empty()) {
413  v.emplace_back("halo_x=" + halo_x_.get_original());
414  }
415 
416  if(!halo_y_.get_original().empty()) {
417  v.emplace_back("halo_y=" + halo_y_.get_original());
418  }
419 
420  if(!halo_mod_.empty()) {
421  v.emplace_back("halo_mod=" + halo_mod_);
422  }
423 
424  if(!sound_.empty()) {
425  v.emplace_back("sound=" + sound_);
426  }
427 
428  if(!text_.empty()) {
429  v.emplace_back("text=" + text_);
430 
431  if(text_color_) {
432  v.emplace_back("text_color=" + text_color_->to_rgba_string());
433  }
434  }
435 
436  if(!blend_ratio_.get_original().empty()) {
437  v.emplace_back("blend_ratio=" + blend_ratio_.get_original());
438 
439  if(blend_with_) {
440  v.emplace_back("blend_with=" + blend_with_->to_rgba_string());
441  }
442  }
443 
444  if(!highlight_ratio_.get_original().empty()) {
445  v.emplace_back("highlight_ratio=" + highlight_ratio_.get_original());
446  }
447 
448  if(!offset_.get_original().empty()) {
449  v.emplace_back("offset=" + offset_.get_original());
450  }
451 
452  if(!submerge_.get_original().empty()) {
453  v.emplace_back("submerge=" + submerge_.get_original());
454  }
455 
456  if(!x_.get_original().empty()) {
457  v.emplace_back("x=" + x_.get_original());
458  }
459 
460  if(!y_.get_original().empty()) {
461  v.emplace_back("y=" + y_.get_original());
462  }
463 
464  if(!directional_x_.get_original().empty()) {
465  v.emplace_back("directional_x=" + directional_x_.get_original());
466  }
467 
468  if(!directional_y_.get_original().empty()) {
469  v.emplace_back("directional_y=" + directional_y_.get_original());
470  }
471 
472  if(!boost::indeterminate(auto_vflip_)) {
473  v.emplace_back("auto_vflip=" + utils::bool_string(static_cast<bool>(auto_vflip_)));
474  }
475 
476  if(!boost::indeterminate(auto_hflip_)) {
477  v.emplace_back("auto_hflip=" + utils::bool_string(static_cast<bool>(auto_hflip_)));
478  }
479 
480  if(!boost::indeterminate(primary_frame_)) {
481  v.emplace_back("primary_frame=" + utils::bool_string(static_cast<bool>(primary_frame_)));
482  }
483 
484  if(!drawing_layer_.get_original().empty()) {
485  v.emplace_back("drawing_layer=" + drawing_layer_.get_original());
486  }
487 
488  return v;
489 }
490 
491 namespace
492 {
493 void render_unit_image(
494  int x,
495  int y,
497  const map_location& loc,
498  const image::locator& i_locator,
499  bool hreverse,
500  uint8_t alpha,
501  double highlight,
502  color_t blendto,
503  double blend_ratio,
504  double submerge,
505  bool vreverse)
506 {
507  const point image_size = image::get_size(i_locator);
508  if(!image_size.x || !image_size.y) {
509  return;
510  }
511 
513 
514  rect dest = disp->scaled_to_zoom({x, y, image_size.x, image_size.y});
515  if(!dest.overlaps(disp->map_area())) {
516  return;
517  }
518 
519  texture tex = image::get_texture(i_locator);
520 
521  // Clamp blend ratio so nothing weird happens
522  blend_ratio = std::clamp(blend_ratio, 0.0, 1.0);
523 
524  submerge_data data = display::get_submerge_data(dest, submerge, image_size, alpha, hreverse, vreverse);
525 
526  disp->drawing_buffer_add(drawing_layer, loc, [=](const rect&) mutable {
527  tex.set_alpha_mod(alpha);
528 
529  if(submerge > 0.0) {
530  // set clip for dry part
531  // smooth_shaded doesn't use the clip information so it's fine to set it up front
532  tex.set_src(data.unsub_src);
533 
534  // draw underwater part
535  draw::smooth_shaded(tex, data.alpha_verts);
536 
537  // draw dry part
538  draw::flipped(tex, data.unsub_dest, hreverse, vreverse);
539  } else {
540  // draw whole texture
541  draw::flipped(tex, dest, hreverse, vreverse);
542  }
543 
544  if(uint8_t hl = float_to_color(highlight); hl > 0) {
545  tex.set_blend_mode(SDL_BLENDMODE_ADD);
546  tex.set_alpha_mod(hl);
547 
548  if(submerge > 0.0) {
549  // draw underwater part
550  draw::smooth_shaded(tex, data.alpha_verts);
551 
552  // draw dry part
553  draw::flipped(tex, data.unsub_dest, hreverse, vreverse);
554  } else {
555  // draw whole texture
556  draw::flipped(tex, dest, hreverse, vreverse);
557  }
558  }
559 
560  tex.set_blend_mode(SDL_BLENDMODE_BLEND);
561  tex.set_alpha_mod(SDL_ALPHA_OPAQUE);
562  });
563 
564  // SDL hax to apply an active washout tint at the correct ratio
565  if(blend_ratio == 0.0) {
566  return;
567  }
568 
569  // Get a pure-white version of the texture
570  const image::locator whiteout_locator(
571  i_locator.get_filename(),
572  i_locator.get_modifications()
573  + "~CHAN(255, 255, 255, alpha)"
574  );
575 
576  disp->drawing_buffer_add(drawing_layer, loc, [=, tex = image::get_texture(whiteout_locator)](const rect&) mutable {
577  tex.set_alpha_mod(alpha * blend_ratio);
578  tex.set_color_mod(blendto);
579 
580  if(submerge > 0.0) {
581  SDL_FColor fcolor;
582  fcolor.r = blendto.r;
583  fcolor.g = blendto.g;
584  fcolor.b = blendto.b;
585 
586  // also draw submerged portion
587  // alpha_mod and color_mod are ignored,
588  // so we have to put them in the smooth shaded vertex data.
589  // This also has to incorporate the existing submerge alpha.
590  blendto.a = uint8_t(data.alpha_verts[0].color.a * blend_ratio);
591  data.alpha_verts[0].color = fcolor;
592  data.alpha_verts[1].color = fcolor;
593 
594  blendto.a = uint8_t(data.alpha_verts[2].color.a * blend_ratio);
595  data.alpha_verts[2].color = fcolor;
596  data.alpha_verts[3].color = fcolor;
597 
598  // set clip for dry part
599  // smooth_shaded doesn't use the clip information so it's fine to set it up front
600  tex.set_src(data.unsub_src);
601 
602  // draw underwater part
603  draw::smooth_shaded(tex, data.alpha_verts);
604 
605  // draw dry part
606  draw::flipped(tex, data.unsub_dest, hreverse, vreverse);
607  } else {
608  // draw whole texture
609  draw::flipped(tex, dest, hreverse, vreverse);
610  }
611 
612  if(uint8_t hl = float_to_color(highlight); hl > 0) {
613  tex.set_blend_mode(SDL_BLENDMODE_ADD);
614  tex.set_alpha_mod(hl);
615 
616  if(submerge > 0.0) {
617  // draw underwater part
618  draw::smooth_shaded(tex, data.alpha_verts);
619 
620  // draw dry part
621  draw::flipped(tex, data.unsub_dest, hreverse, vreverse);
622  } else {
623  // draw whole texture
624  draw::flipped(tex, dest, hreverse, vreverse);
625  }
626  }
627 
628  tex.set_color_mod(255, 255, 255);
629  tex.set_blend_mode(SDL_BLENDMODE_BLEND);
630  tex.set_alpha_mod(SDL_ALPHA_OPAQUE);
631  });
632 }
633 } // namespace
634 
635 void unit_frame::redraw(const std::chrono::milliseconds& frame_time, bool on_start_time, bool in_scope_of_frame,
636  const map_location& src, const map_location& dst,
637  halo::handle& halo_id, halo::manager& halo_man,
638  const frame_parameters& animation_val, const frame_parameters& engine_val) const
639 {
641 
642  const auto [xsrc, ysrc] = game_disp->get_location(src);
643  const auto [xdst, ydst] = game_disp->get_location(dst);
644  const map_location::direction direction = src.get_relative_dir(dst);
645 
646  const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
647  double tmp_offset = current_data.offset;
648 
649  // Debug code to see the number of frames and their position
650  //if(tmp_offset) {
651  // std::cout << static_cast<int>(tmp_offset * 100) << "," << "\n";
652  //}
653 
654  if(on_start_time) {
655  // Stuff that should be done only once per frame
656  if(!current_data.sound.empty() ) {
657  sound::play_sound(current_data.sound);
658  }
659 
660  if(!current_data.text.empty() && current_data.text_color) {
661  game_disp->float_label(src, current_data.text, *current_data.text_color);
662  }
663  }
664 
665  image::locator image_loc;
666  if(direction != map_location::direction::north && direction != map_location::direction::south) {
667  image_loc = current_data.image_diagonal.clone(current_data.image_mod);
668  }
669 
670  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
671  image_loc = current_data.image.clone(current_data.image_mod);
672  }
673 
674  point image_size {0, 0};
675  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
676  image_size = image::get_size(image_loc);
677  }
678 
679  const int d2 = display::get_singleton()->hex_size() / 2;
680 
681  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc) + d2;
682  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc) + d2;
683  const double disp_zoom = display::get_singleton()->get_zoom_factor();
684 
685  if(image_size.x && image_size.y) {
686  bool facing_west = (
689 
690  bool facing_north = (
692  direction == map_location::direction::north ||
694 
695  if(!current_data.auto_hflip) { facing_west = false; }
696  if(!current_data.auto_vflip) { facing_north = true; }
697 
698  int my_x = x + disp_zoom * (current_data.x - image_size.x / 2);
699  int my_y = y + disp_zoom * (current_data.y - image_size.y / 2);
700 
701  if(facing_west) {
702  my_x -= current_data.directional_x * disp_zoom;
703  } else {
704  my_x += current_data.directional_x * disp_zoom;
705  }
706 
707  if(facing_north) {
708  my_y += current_data.directional_y * disp_zoom;
709  } else {
710  my_y -= current_data.directional_y * disp_zoom;
711  }
712 
713  // TODO: don't conflate highlights and alpha
714  double brighten;
715  uint8_t alpha;
716  if(current_data.highlight_ratio >= 1.0) {
717  brighten = current_data.highlight_ratio - 1.0;
718  alpha = 255;
719  } else {
720  brighten = 0.0;
721  alpha = float_to_color(current_data.highlight_ratio);
722  }
723 
724  if(alpha != 0) {
725  render_unit_image(my_x, my_y,
726  drawing_layer { int(drawing_layer::unit_first) + current_data.drawing_layer },
727  src,
728  image_loc,
729  facing_west,
730  alpha,
731  brighten,
732  current_data.blend_with ? *current_data.blend_with : color_t(),
733  current_data.blend_ratio,
734  current_data.submerge,
735  !facing_north
736  );
737  }
738  }
739 
740  halo_id.reset();
741 
742  if(!in_scope_of_frame) { //check after frame as first/last frame image used in defense/attack anims
743  return;
744  }
745 
746  // No halos, exit
747  if(current_data.halo.empty()) {
748  return;
749  }
750 
751  halo::ORIENTATION orientation;
752  switch(direction)
753  {
756  orientation = halo::NORMAL;
757  break;
760  if(!current_data.auto_vflip) {
761  orientation = halo::NORMAL;
762  } else {
763  orientation = halo::VREVERSE;
764  }
765  break;
767  if(!current_data.auto_vflip) {
768  orientation = halo::HREVERSE;
769  } else {
770  orientation = halo::HVREVERSE;
771  }
772  break;
774  orientation = halo::HREVERSE;
775  break;
777  default:
778  orientation = halo::NORMAL;
779  break;
780  }
781 
783  halo_id = halo_man.add(
784  static_cast<int>(x + current_data.halo_x * disp_zoom),
785  static_cast<int>(y + current_data.halo_y * disp_zoom),
786  current_data.halo + current_data.halo_mod,
787  map_location(-1, -1),
788  orientation
789  );
790  } else {
791  halo_id = halo_man.add(
792  static_cast<int>(x - current_data.halo_x * disp_zoom),
793  static_cast<int>(y + current_data.halo_y * disp_zoom),
794  current_data.halo + current_data.halo_mod,
795  map_location(-1, -1),
796  orientation
797  );
798  }
799 }
800 
801 std::set<map_location> unit_frame::get_overlaped_hex(const std::chrono::milliseconds& frame_time, const map_location& src, const map_location& dst,
802  const frame_parameters& animation_val, const frame_parameters& engine_val) const
803 {
805 
806  const auto [xsrc, ysrc] = disp->get_location(src);
807  const auto [xdst, ydst] = disp->get_location(dst);
808  const map_location::direction direction = src.get_relative_dir(dst);
809 
810  const frame_parameters current_data = merge_parameters(frame_time, animation_val, engine_val);
811 
812  double tmp_offset = current_data.offset;
813  const int d2 = display::get_singleton()->hex_size() / 2;
814 
815  image::locator image_loc;
816  if(direction != map_location::direction::north && direction != map_location::direction::south) {
817  image_loc = current_data.image_diagonal.clone(current_data.image_mod);
818  }
819 
820  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
821  image_loc = current_data.image.clone(current_data.image_mod);
822  }
823 
824  // We always invalidate our own hex because we need to be called at redraw time even
825  // if we don't draw anything in the hex itself
826  std::set<map_location> result;
827  if(tmp_offset == 0 && current_data.x == 0 && current_data.directional_x == 0 && image::is_in_hex(image_loc)) {
828  result.insert(src);
829 
830  bool facing_north = (
832  direction == map_location::direction::north ||
834 
835  if(!current_data.auto_vflip) { facing_north = true; }
836 
837  int my_y = current_data.y;
838  if(facing_north) {
839  my_y += current_data.directional_y;
840  } else {
841  my_y -= current_data.directional_y;
842  }
843 
844  if(my_y < 0) {
845  result.insert(src.get_direction(map_location::direction::north));
846  result.insert(src.get_direction(map_location::direction::north_east));
847  result.insert(src.get_direction(map_location::direction::north_west));
848  } else if(my_y > 0) {
849  result.insert(src.get_direction(map_location::direction::south));
850  result.insert(src.get_direction(map_location::direction::south_east));
851  result.insert(src.get_direction(map_location::direction::south_west));
852  }
853  } else {
854  int w = 0, h = 0;
855 
856  if(!image_loc.is_void() && !image_loc.get_filename().empty()) {
857  const point s = image::get_size(image_loc);
858  w = s.x;
859  h = s.y;
860  }
861 
862  if(w != 0 || h != 0) {
863  // TODO: unduplicate this code
864  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc) + d2;
865  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc) + d2;
866  const double disp_zoom = display::get_singleton()->get_zoom_factor();
867 
868  bool facing_west = (
871 
872  bool facing_north = (
874  direction == map_location::direction::north ||
876 
877  if(!current_data.auto_hflip) { facing_west = false; }
878  if(!current_data.auto_vflip) { facing_north = true; }
879 
880  int my_x = x + disp_zoom * (current_data.x - w / 2);
881  int my_y = y + disp_zoom * (current_data.y - h / 2);
882 
883  if(facing_west) {
884  my_x -= current_data.directional_x * disp_zoom;
885  } else {
886  my_x += current_data.directional_x * disp_zoom;
887  }
888 
889  if(facing_north) {
890  my_y += current_data.directional_y * disp_zoom;
891  } else {
892  my_y -= current_data.directional_y * disp_zoom;
893  }
894 
895  // Check if our underlying hexes are invalidated. If we need to update ourselves because we changed,
896  // invalidate our hexes and return whether or not was successful.
897  const rect r {my_x, my_y, int(w * disp_zoom), int(h * disp_zoom)};
898  display::rect_of_hexes underlying_hex = disp->hexes_under_rect(r);
899 
900  result.insert(src);
901  result.insert(underlying_hex.begin(), underlying_hex.end());
902  } else {
903  // We have no "redraw surface" but we still need to invalidate our own hex in case we have a halo
904  // and/or sound that needs a redraw.
905  result.insert(src);
906  result.insert(dst);
907  }
908  }
909 
910  return result;
911 }
912 
913 /**
914  * This function merges the value provided by:
915  * - the frame
916  * - the engine (poison, flying unit...)
917  * - the animation as a whole
918  *
919  * There is no absolute rule for merging, so creativity is the rule. If a value is never provided by the engine, assert.
920  * This way if it becomes used, people will easily find the right place to look.
921  */
922 frame_parameters unit_frame::merge_parameters(const std::chrono::milliseconds& current_time,
923  const frame_parameters& animation_val,
924  const frame_parameters& engine_val) const
925 {
926  frame_parameters result;
927  const frame_parameters& current_val = builder_.parameters(current_time);
928 
929  result.primary_frame = engine_val.primary_frame;
930  if(!boost::logic::indeterminate(animation_val.primary_frame)) {
931  result.primary_frame = animation_val.primary_frame;
932  }
933 
934  if(!boost::logic::indeterminate(current_val.primary_frame)) {
935  result.primary_frame = current_val.primary_frame;
936  }
937 
938  // Convert the tribool to bool
939  const bool primary = static_cast<bool>(result.primary_frame) || boost::logic::indeterminate(result.primary_frame);
940 
941  /** The engine provides a default image to use for the unit when none is available */
942  result.image = current_val.image.is_void() || current_val.image.get_filename().empty()
943  ? animation_val.image
944  : current_val.image;
945 
946  if(primary && (result.image.is_void() || result.image.get_filename().empty())) {
947  result.image = engine_val.image;
948  }
949 
950  /** The engine provides a default image to use for the unit when none is available */
951  result.image_diagonal = current_val.image_diagonal.is_void() || current_val.image_diagonal.get_filename().empty()
952  ? animation_val.image_diagonal
953  : current_val.image_diagonal;
954 
955  if(primary && (result.image_diagonal.is_void() || result.image_diagonal.get_filename().empty())) {
956  result.image_diagonal = engine_val.image_diagonal;
957  }
958 
959  /**
960  * The engine provides a string for "petrified" and "team color" modifications.
961  * Note that image_mod is the complete modification and halo_mod is only the TC part.
962  */
963  result.image_mod = current_val.image_mod + animation_val.image_mod;
964  if(primary) {
965  result.image_mod += engine_val.image_mod;
966  } else {
967  result.image_mod += engine_val.halo_mod;
968  }
969 
970  assert(engine_val.halo.empty());
971  result.halo = current_val.halo.empty() ? animation_val.halo : current_val.halo;
972 
973  assert(engine_val.halo_x == 0);
974  result.halo_x = current_val.halo_x ? current_val.halo_x : animation_val.halo_x;
975 
976  /** The engine provides a y modification for terrain with height adjust and flying units */
977  result.halo_y = current_val.halo_y ? current_val.halo_y : animation_val.halo_y;
978  result.halo_y += engine_val.halo_y;
979 
980  result.halo_mod = current_val.halo_mod + animation_val.halo_mod;
981  result.halo_mod += engine_val.halo_mod;
982 
983  assert(engine_val.duration == 0ms);
984  result.duration = current_val.duration;
985 
986  assert(engine_val.sound.empty());
987  result.sound = current_val.sound.empty() ? animation_val.sound : current_val.sound;
988 
989  assert(engine_val.text.empty());
990  result.text = current_val.text.empty() ? animation_val.text : current_val.text;
991 
992  assert(!engine_val.text_color);
993  result.text_color = current_val.text_color ? current_val.text_color : animation_val.text_color;
994 
995  /** The engine provides a blend color for poisoned units */
996  result.blend_with = current_val.blend_with ? current_val.blend_with : animation_val.blend_with;
997  if(primary && engine_val.blend_with) {
998  result.blend_with = engine_val.blend_with->blend_lighten(result.blend_with ? *result.blend_with : color_t(0,0,0));
999  }
1000 
1001  /** The engine provides a blend color for poisoned units */
1002  result.blend_ratio = current_val.blend_ratio != 0 ? current_val.blend_ratio:animation_val.blend_ratio;
1003  if(primary && engine_val.blend_ratio != 0) {
1004  result.blend_ratio = std::min(result.blend_ratio + engine_val.blend_ratio, 1.0);
1005  }
1006 
1007  /** The engine provides a highlight ratio for selected units and visible "invisible" units */
1008  result.highlight_ratio = (current_val.highlight_ratio < 0.999 || current_val.highlight_ratio > 1.001) ?
1009  current_val.highlight_ratio : animation_val.highlight_ratio;
1010  if(primary && (engine_val.highlight_ratio < 0.999 || engine_val.highlight_ratio > 1.001)) {
1011  result.highlight_ratio = result.highlight_ratio * engine_val.highlight_ratio; // selected unit
1012  }
1013 
1014  assert(engine_val.offset == 0);
1015  result.offset = (current_val.offset != -1000) ? current_val.offset : animation_val.offset;
1016  if(result.offset == -1000) {
1017  result.offset = 0.0;
1018  }
1019 
1020  /** The engine provides a submerge for units in water */
1021  result.submerge = current_val.submerge != 0 ? current_val.submerge : animation_val.submerge;
1022  if(primary && engine_val.submerge != 0 && result.submerge == 0) {
1023  result.submerge = engine_val.submerge;
1024  }
1025 
1026  assert(engine_val.x == 0);
1027  result.x = current_val.x ? current_val.x : animation_val.x;
1028 
1029  /** The engine provides a y modification for terrain with height adjust and flying units */
1030  result.y = current_val.y?current_val.y:animation_val.y;
1031  result.y += engine_val.y;
1032 
1033  assert(engine_val.directional_x == 0);
1034  result.directional_x = current_val.directional_x ? current_val.directional_x : animation_val.directional_x;
1035 
1036  assert(engine_val.directional_y == 0);
1037  result.directional_y = current_val.directional_y ? current_val.directional_y : animation_val.directional_y;
1038 
1041  ? current_val.drawing_layer
1042  : animation_val.drawing_layer;
1043 
1044  /** The engine provides us with a default value to compare to. Update if different */
1045  result.auto_hflip = engine_val.auto_hflip;
1046 
1047  if(!boost::logic::indeterminate(animation_val.auto_hflip)) {
1048  result.auto_hflip = animation_val.auto_hflip;
1049  }
1050 
1051  if(!boost::logic::indeterminate(current_val.auto_hflip)) {
1052  result.auto_hflip = current_val.auto_hflip;
1053  }
1054 
1055  if(boost::logic::indeterminate(result.auto_hflip)) {
1056  result.auto_hflip = true;
1057  }
1058 
1059  result.auto_vflip = engine_val.auto_vflip;
1060 
1061  if(!boost::logic::indeterminate(animation_val.auto_vflip)) {
1062  result.auto_vflip = animation_val.auto_vflip;
1063  }
1064 
1065  if(!boost::logic::indeterminate(current_val.auto_vflip)) {
1066  result.auto_vflip = current_val.auto_vflip;
1067  }
1068 
1069  if(boost::logic::indeterminate(result.auto_vflip)) {
1070  result.auto_vflip = !primary;
1071  }
1072 
1073  return result;
1074 }
map_location loc
Definition: move.cpp:172
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
const attribute_value * get(std::string_view key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:665
bool has_attribute(std::string_view key) const
Definition: config.cpp:157
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:88
point get_location(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:668
static int hex_size()
Function which returns the size of a hex in pixels (from left tip to right tip or top edge to bottom ...
Definition: display.hpp:256
static double get_zoom_factor()
Returns the current zoom factor.
Definition: display.hpp:259
static submerge_data get_submerge_data(const rect &dest, double submerge, const point &size, uint8_t alpha, bool hreverse, bool vreverse)
Definition: display.cpp:2035
static rect scaled_to_zoom(const rect &r)
Scale the width and height of a rect by the current zoom factor.
Definition: display.hpp:265
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:1234
const rect_of_hexes hexes_under_rect(const rect &r) const
Return the rectangular area of hexes overlapped by r (r is in screen coordinates)
Definition: display.cpp:615
rect map_area() const
Returns the area used for the map.
Definition: display.cpp:484
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:102
Easily build frame parameters with the serialized constructors.
Definition: frame.hpp:84
std::string offset_
Definition: frame.hpp:129
std::string halo_y_
Definition: frame.hpp:119
std::string image_mod_
Definition: frame.hpp:116
utils::optional< color_t > blend_with_
Definition: frame.hpp:125
std::string halo_mod_
Definition: frame.hpp:120
std::string image_diagonal_
Definition: frame.hpp:115
frame_builder()
Definition: frame.cpp:28
boost::tribool auto_vflip_
Definition: frame.hpp:136
boost::tribool primary_frame_
Definition: frame.hpp:138
frame_builder & auto_hflip(const bool auto_hflip)
Definition: frame.cpp:208
std::string halo_
Definition: frame.hpp:117
frame_builder & highlight(const std::string &highlight)
Definition: frame.cpp:160
std::string sound_
Definition: frame.hpp:121
frame_builder & image_diagonal(const std::string &image_diagonal, const std::string &image_mod="")
Definition: frame.cpp:118
frame_builder & directional_x(const std::string &directional_x)
Definition: frame.cpp:190
frame_builder & submerge(const std::string &submerge)
Definition: frame.cpp:172
std::string image_
Definition: frame.hpp:114
std::string submerge_
Definition: frame.hpp:130
frame_builder & y(const std::string &y)
Definition: frame.cpp:184
frame_builder & primary_frame(const bool primary_frame)
Definition: frame.cpp:214
frame_builder & auto_vflip(const bool auto_vflip)
Definition: frame.cpp:202
std::string y_
Definition: frame.hpp:132
std::string highlight_ratio_
Definition: frame.hpp:128
boost::tribool auto_hflip_
Definition: frame.hpp:137
std::string blend_ratio_
Definition: frame.hpp:127
std::string text_
Definition: frame.hpp:122
std::string drawing_layer_
Definition: frame.hpp:140
frame_builder & drawing_layer(const std::string &drawing_layer)
Definition: frame.cpp:220
std::string directional_x_
Definition: frame.hpp:133
std::string directional_y_
Definition: frame.hpp:134
std::string halo_x_
Definition: frame.hpp:118
frame_builder & text(const std::string &text, const color_t text_color)
Definition: frame.cpp:131
frame_builder & blend(const std::string &blend_ratio, const color_t blend_color)
Definition: frame.cpp:153
frame_builder & x(const std::string &x)
Definition: frame.cpp:178
utils::optional< color_t > text_color_
Definition: frame.hpp:124
frame_builder & offset(const std::string &offset)
Definition: frame.cpp:166
frame_builder & directional_y(const std::string &directional_y)
Definition: frame.cpp:196
frame_builder & image(const std::string &image, const std::string &image_mod="")
Definition: frame.cpp:111
frame_builder & sound(const std::string &sound)
Definition: frame.cpp:125
std::string x_
Definition: frame.hpp:131
frame_builder & duration(const std::chrono::milliseconds &duration)
Allow easy chained modifications.
Definition: frame.cpp:147
frame_builder & halo(const std::string &halo, const std::string &halo_x, const std::string &halo_y, const std::string &halo_mod)
Definition: frame.cpp:138
std::chrono::milliseconds duration_
Definition: frame.hpp:112
void override(const std::chrono::milliseconds &duration, const std::string &highlight="", const std::string &blend_ratio="", color_t blend_color={0, 0, 0}, const std::string &offset="", const std::string &layer="", const std::string &modifiers="")
Definition: frame.cpp:336
std::string text_
Definition: frame.hpp:185
progressive_int directional_x_
Definition: frame.hpp:196
progressive_int halo_y_
Definition: frame.hpp:181
boost::tribool auto_hflip_
Definition: frame.hpp:200
progressive_image image_
Definition: frame.hpp:174
boost::tribool primary_frame_
Definition: frame.hpp:201
bool need_update() const
Definition: frame.cpp:272
progressive_double blend_ratio_
Definition: frame.hpp:190
progressive_double highlight_ratio_
Definition: frame.hpp:191
progressive_double offset_
Definition: frame.hpp:192
boost::tribool auto_vflip_
Definition: frame.hpp:199
progressive_string halo_
Definition: frame.hpp:179
frame_parameters parameters(const std::chrono::milliseconds &current_time) const
Getters for the different parameters.
Definition: frame.cpp:277
utils::optional< color_t > blend_with_
Definition: frame.hpp:188
progressive_int x_
Definition: frame.hpp:194
std::string sound_
Definition: frame.hpp:184
std::chrono::milliseconds duration_
Definition: frame.hpp:172
progressive_double submerge_
Definition: frame.hpp:193
std::string halo_mod_
Definition: frame.hpp:183
std::string image_mod_
Definition: frame.hpp:177
progressive_int halo_x_
Definition: frame.hpp:180
progressive_int y_
Definition: frame.hpp:195
progressive_int drawing_layer_
Definition: frame.hpp:203
utils::optional< color_t > text_color_
Definition: frame.hpp:187
const std::chrono::milliseconds & duration() const
Definition: frame.hpp:164
std::vector< std::string > debug_strings() const
Contents of frame in strings.
Definition: frame.cpp:388
progressive_int directional_y_
Definition: frame.hpp:197
progressive_image image_diagonal_
Definition: frame.hpp:175
frame_parsed_parameters(const frame_builder &builder=frame_builder(), const std::chrono::milliseconds &override_duration=std::chrono::milliseconds{0})
Definition: frame.cpp:226
bool does_not_change() const
Definition: frame.cpp:253
static game_display * get_singleton()
void float_label(const map_location &loc, const std::string &text, const color_t &color)
Function to float a label above a tile.
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 'image centered on (x,y).
Definition: halo.cpp:408
Generic locator abstracting the location of an image.
Definition: picture.hpp:59
bool is_void() const
Returns true if the locator does not correspond to an actual image.
Definition: picture.hpp:93
const std::string & get_filename() const
Definition: picture.hpp:82
const std::string & get_modifications() const
Definition: picture.hpp:87
locator clone(const std::string &mods) const
Returns a copy of this locator with the given IPF.
Definition: picture.cpp:228
std::string get_original() const
virtual bool does_not_change() const
std::chrono::milliseconds duration() const
virtual const T get_current_element(const std::chrono::milliseconds &current_time, T default_val=T()) const override
bool does_not_change() const override
virtual const T get_current_element(const std::chrono::milliseconds &current_time, T default_val=T()) const override
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:33
void set_blend_mode(SDL_BlendMode mode)
Blend mode.
Definition: texture.cpp:185
void set_src(const rect &r)
Set the source region of the texture used for drawing operations.
Definition: texture.cpp:122
void set_alpha_mod(uint8_t alpha)
Alpha modifier.
Definition: texture.cpp:146
void set_color_mod(uint8_t r, uint8_t g, uint8_t b)
Colour modifier.
Definition: texture.cpp:168
void redraw(const std::chrono::milliseconds &frame_time, bool on_start_time, bool in_scope_of_frame, const map_location &src, const map_location &dst, halo::handle &halo_id, halo::manager &halo_man, const frame_parameters &animation_val, const frame_parameters &engine_val) const
Definition: frame.cpp:635
std::set< map_location > get_overlaped_hex(const std::chrono::milliseconds &frame_time, const map_location &src, const map_location &dst, const frame_parameters &animation_val, const frame_parameters &engine_val) const
Definition: frame.cpp:801
frame_parameters merge_parameters(const std::chrono::milliseconds &current_time, const frame_parameters &animation_val, const frame_parameters &engine_val=frame_parameters()) const
This function merges the value provided by:
Definition: frame.cpp:922
frame_parsed_parameters builder_
Definition: frame.hpp:255
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:274
Drawing functions, for drawing things on the screen.
drawing_layer
@ unit_default
Default layer for drawing units.
@ unit_first
Reserve layers to be selected for wml.
const config * cfg
static lg::log_domain log_engine("engine")
#define ERR_NG
Definition: frame.cpp:26
Frame for unit's animation sequence.
constexpr int get_abs_frame_layer(drawing_layer layer)
Definition: frame.hpp:37
progressive_pair< double > progressive_double
progressive_single< image::locator > progressive_image
progressive_single< std::string > progressive_string
progressive_pair< int > progressive_int
Standard logging facilities (interface).
Definition: span.hpp:53
void flipped(const texture &tex, const ::rect &dst, bool flip_h=true, bool flip_v=false)
Draws a texture, or part of a texture, at the given location, also mirroring/flipping the texture hor...
Definition: draw.cpp:452
void smooth_shaded(const texture &tex, const std::array< SDL_Vertex, 4 > &verts)
Draw a texture with smoothly varying colour and alpha modification, specified at the four corners of ...
Definition: draw.cpp:556
Definition: halo.cpp:41
ORIENTATION
Definition: halo.hpp:35
@ HVREVERSE
Definition: halo.hpp:35
@ VREVERSE
Definition: halo.hpp:35
@ HREVERSE
Definition: halo.hpp:35
@ NORMAL
Definition: halo.hpp:35
std::shared_ptr< halo_record > handle
Definition: halo.hpp:31
Functions to load and save images from/to disk.
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:955
point get_size(const locator &i_locator, bool skip_cache)
Returns the width and height of an image.
Definition: picture.cpp:815
bool is_in_hex(const locator &i_locator)
Checks if an image fits into a single hex.
Definition: picture.cpp:824
Audio output for sound and music.
Definition: sound.cpp:40
void play_sound(const std::string &files, sound_tracks::type group, unsigned int repeats)
Definition: sound.cpp:917
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
std::string bool_string(const bool value)
Converts a bool value to 'true' or 'false'.
std::string to_string(const Range &range, const Func &op)
int w
Definition: pathfind.cpp:188
std::string_view data
Definition: picture.cpp:188
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:51
static color_t from_rgb_string(std::string_view c)
Creates a new opaque color_t object from a string variable in "R,G,B" format.
Definition: color.cpp:44
Rectangular area of hexes, allowing to decide how the top and bottom edges handles the vertical shift...
Definition: display.hpp:317
iterator end() const
Definition: display.cpp:610
iterator begin() const
Definition: display.cpp:606
All parameters from a frame at a given instant.
Definition: frame.hpp:44
std::string halo
Definition: frame.hpp:51
utils::optional< color_t > blend_with
Definition: frame.hpp:61
double highlight_ratio
Definition: frame.hpp:64
std::string text
Definition: frame.hpp:58
boost::tribool auto_hflip
Definition: frame.hpp:74
int directional_x
Definition: frame.hpp:70
double offset
Definition: frame.hpp:65
std::string sound
Definition: frame.hpp:57
std::string image_mod
Definition: frame.hpp:50
double submerge
Definition: frame.hpp:66
int drawing_layer
Definition: frame.hpp:77
image::locator image_diagonal
Definition: frame.hpp:48
boost::tribool primary_frame
Definition: frame.hpp:75
int directional_y
Definition: frame.hpp:71
image::locator image
Definition: frame.hpp:47
std::chrono::milliseconds duration
Definition: frame.hpp:45
utils::optional< color_t > text_color
Definition: frame.hpp:60
double blend_ratio
Definition: frame.hpp:63
std::string halo_mod
Definition: frame.hpp:56
boost::tribool auto_vflip
Definition: frame.hpp:73
Encapsulates the map of the game.
Definition: location.hpp:46
direction
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:48
Holds a 2D point.
Definition: point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:49
bool overlaps(const rect &r) const
Whether the given rectangle and this rectangle overlap.
Definition: rect.cpp:74
static map_location::direction s
#define e
#define h