The Battle for Wesnoth  1.17.0-dev
frame.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2021
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 "game_display.hpp"
20 #include "log.hpp"
21 #include "sound.hpp"
22 
23 static lg::log_domain log_engine("engine");
24 #define ERR_NG LOG_STREAM(err, log_engine)
25 
27  : duration(0)
28  , halo_x(0)
29  , halo_y(0)
30  , blend_ratio(0.0)
31  , highlight_ratio(1.0)
32  , offset(0)
33  , submerge(0.0)
34  , x(0)
35  , y(0)
36  , directional_x(0)
37  , directional_y(0)
38  , auto_vflip(boost::logic::indeterminate)
39  , auto_hflip(boost::logic::indeterminate)
40  , primary_frame(boost::logic::indeterminate)
41  , drawing_layer(display::LAYER_UNIT_DEFAULT - display::LAYER_UNIT_FIRST)
42 {}
43 
45  : duration_(1)
46  , auto_vflip_(boost::logic::indeterminate)
47  , auto_hflip_(boost::logic::indeterminate)
48  , primary_frame_(boost::logic::indeterminate)
49  , drawing_layer_(std::to_string(display::LAYER_UNIT_DEFAULT - display::LAYER_UNIT_FIRST))
50 {}
51 
52 frame_builder::frame_builder(const config& cfg,const std::string& frame_string)
53  : duration_(1)
54  , image_(cfg[frame_string + "image"])
55  , image_diagonal_(cfg[frame_string + "image_diagonal"])
56  , image_mod_(cfg[frame_string + "image_mod"])
57  , halo_(cfg[frame_string + "halo"])
58  , halo_x_(cfg[frame_string + "halo_x"])
59  , halo_y_(cfg[frame_string + "halo_y"])
60  , halo_mod_(cfg[frame_string + "halo_mod"])
61  , sound_(cfg[frame_string + "sound"])
62  , text_(cfg[frame_string + "text"])
63  , blend_ratio_(cfg[frame_string + "blend_ratio"])
64  , highlight_ratio_(cfg[frame_string + "alpha"])
65  , offset_(cfg[frame_string + "offset"])
66  , submerge_(cfg[frame_string + "submerge"])
67  , x_(cfg[frame_string + "x"])
68  , y_(cfg[frame_string + "y"])
69  , directional_x_(cfg[frame_string + "directional_x"])
70  , directional_y_(cfg[frame_string + "directional_y"])
71  , auto_vflip_(boost::logic::indeterminate)
72  , auto_hflip_(boost::logic::indeterminate)
73  , primary_frame_(boost::logic::indeterminate)
74  , drawing_layer_(cfg[frame_string + "layer"])
75 {
76  if(cfg.has_attribute(frame_string + "auto_vflip")) {
77  auto_vflip_ = cfg[frame_string + "auto_vflip"].to_bool();
78  }
79 
80  if(cfg.has_attribute(frame_string + "auto_hflip")) {
81  auto_hflip_ = cfg[frame_string + "auto_hflip"].to_bool();
82  }
83 
84  if(cfg.has_attribute(frame_string + "primary")) {
85  primary_frame_ = cfg[frame_string + "primary"].to_bool();
86  }
87 
88  const auto& text_color_key = cfg[frame_string + "text_color"];
89  if(!text_color_key.empty()) {
90  try {
91  text_color_ = color_t::from_rgb_string(text_color_key);
92  } catch(const std::invalid_argument& e) {
93  // Might be thrown either due to an incorrect number of elements or std::stoul failure.
94  ERR_NG << "Invalid RBG text color in unit animation: " << text_color_key.str()
95  << "\n" << e.what() << "\n;";
96  }
97  }
98 
99  if(const config::attribute_value* v = cfg.get(frame_string + "duration")) {
100  duration(*v);
101  } else if(!cfg.get(frame_string + "end")) {
102  int halo_duration = (progressive_string(halo_, 1)).duration();
103  int image_duration = (progressive_image(image_, 1)).duration();
104  int image_diagonal_duration = (progressive_image(image_diagonal_, 1)).duration();
105 
106  duration(std::max(std::max(image_duration, image_diagonal_duration), halo_duration));
107  } else {
108  duration(cfg[frame_string + "end"].to_int() - cfg[frame_string + "begin"].to_int());
109  }
110 
111  duration_ = std::max(duration_, 1);
112 
113  const auto& blend_color_key = cfg[frame_string + "blend_color"];
114  if(!blend_color_key.empty()) {
115  try {
116  blend_with_ = color_t::from_rgb_string(blend_color_key);
117  } catch(const std::invalid_argument& e) {
118  // Might be thrown either due to an incorrect number of elements or std::stoul failure.
119  ERR_NG << "Invalid RBG blend color in unit animation: " << blend_color_key.str()
120  << "\n" << e.what() << "\n;";
121  }
122  }
123 }
124 
125 frame_builder& frame_builder::image(const std::string& image ,const std::string& image_mod)
126 {
127  image_ = image;
128  image_mod_ = image_mod;
129  return *this;
130 }
131 
132 frame_builder& frame_builder::image_diagonal(const std::string& image_diagonal,const std::string& image_mod)
133 {
135  image_mod_ = image_mod;
136  return *this;
137 }
138 
140 {
141  sound_ = sound;
142  return *this;
143 }
144 
145 frame_builder& frame_builder::text(const std::string& text,const color_t text_color)
146 {
147  text_ = text;
148  text_color_ = text_color;
149  return *this;
150 }
151 
152 frame_builder& frame_builder::halo(const std::string& halo, const std::string& halo_x, const std::string& halo_y,const std::string& halo_mod)
153 {
154  halo_ = halo;
155  halo_x_ = halo_x;
156  halo_y_ = halo_y;
157  halo_mod_= halo_mod;
158  return *this;
159 }
160 
162 {
164  return *this;
165 }
166 
167 frame_builder& frame_builder::blend(const std::string& blend_ratio,const color_t blend_color)
168 {
169  blend_with_ = blend_color;
170  blend_ratio_ = blend_ratio;
171  return *this;
172 }
173 
175 {
177  return *this;
178 }
179 
181 {
182  offset_ = offset;
183  return *this;
184 }
185 
187 {
189  return *this;
190 }
191 
192 frame_builder& frame_builder::x(const std::string& x)
193 {
194  x_ = x;
195  return *this;
196 }
197 
198 frame_builder& frame_builder::y(const std::string& y)
199 {
200  y_ = y;
201  return *this;
202 }
203 
205 {
207  return *this;
208 }
209 
211 {
213  return *this;
214 }
215 
217 {
219  return *this;
220 }
221 
223 {
225  return *this;
226 }
227 
229 {
231  return *this;
232 }
233 
235 {
237  return *this;
238 }
239 
241  : duration_(duration ? duration : builder.duration_)
242  , image_(builder.image_,duration_)
244  , image_mod_(builder.image_mod_)
245  , halo_(builder.halo_,duration_)
246  , halo_x_(builder.halo_x_,duration_)
247  , halo_y_(builder.halo_y_,duration_)
248  , halo_mod_(builder.halo_mod_)
249  , sound_(builder.sound_)
250  , text_(builder.text_)
251  , text_color_(builder.text_color_)
252  , blend_with_(builder.blend_with_)
255  , offset_(builder.offset_,duration_)
256  , submerge_(builder.submerge_,duration_)
257  , x_(builder.x_,duration_)
258  , y_(builder.y_,duration_)
261  , auto_vflip_(builder.auto_vflip_)
262  , auto_hflip_(builder.auto_hflip_)
263  , primary_frame_(builder.primary_frame_)
265 {}
266 
268 {
269  return
279  x_.does_not_change() &&
280  y_.does_not_change() &&
284 }
285 
287 {
288  return !this->does_not_change();
289 }
290 
292 {
293  frame_parameters result;
294  result.duration = duration_;
295  result.image = image_.get_current_element(current_time);
296  result.image_diagonal = image_diagonal_.get_current_element(current_time);
297  result.image_mod = image_mod_;
298  result.halo = halo_.get_current_element(current_time);
299  result.halo_x = halo_x_.get_current_element(current_time);
300  result.halo_y = halo_y_.get_current_element(current_time);
301  result.halo_mod = halo_mod_;
302  result.sound = sound_;
303  result.text = text_;
304  result.text_color = text_color_;
305  result.blend_with = blend_with_;
306  result.blend_ratio = blend_ratio_.get_current_element(current_time);
307  result.highlight_ratio = highlight_ratio_.get_current_element(current_time,1.0);
308  result.offset = offset_.get_current_element(current_time,-1000);
309  result.submerge = submerge_.get_current_element(current_time);
310  result.x = x_.get_current_element(current_time);
311  result.y = y_.get_current_element(current_time);
312  result.directional_x = directional_x_.get_current_element(current_time);
313  result.directional_y = directional_y_.get_current_element(current_time);
314  result.auto_vflip = auto_vflip_;
315  result.auto_hflip = auto_hflip_;
316  result.primary_frame = primary_frame_;
318  return result;
319 }
320 
322  const std::string& highlight,
323  const std::string& blend_ratio,
324  color_t blend_color,
325  const std::string& offset,
326  const std::string& layer,
327  const std::string& modifiers)
328 {
329  if(!highlight.empty()) {
330  highlight_ratio_ = progressive_double(highlight,duration);
331  } else if(duration != duration_){
333  }
334 
335  if(!offset.empty()) {
336  offset_ = progressive_double(offset,duration);
337  } else if(duration != duration_){
339  }
340 
341  if(!blend_ratio.empty()) {
342  blend_ratio_ = progressive_double(blend_ratio,duration);
343  blend_with_ = blend_color;
344  } else if(duration != duration_){
346  }
347 
348  if(!layer.empty()) {
349  drawing_layer_ = progressive_int(layer,duration);
350  } else if(duration != duration_){
352  }
353 
354  if(!modifiers.empty()) {
355  image_mod_ += modifiers;
356  }
357 
358  if(duration != duration_) {
370  }
371 }
372 
373 std::vector<std::string> frame_parsed_parameters::debug_strings() const
374 {
375  std::vector<std::string> v;
376 
377  if(duration_ > 0) {
378  v.emplace_back("duration=" + utils::half_signed_value(duration_));
379  }
380 
381  if(!image_.get_original().empty()) {
382  v.emplace_back("image=" + image_.get_original());
383  }
384 
385  if(!image_diagonal_.get_original().empty()) {
386  v.emplace_back("image_diagonal=" + image_diagonal_.get_original());
387  }
388 
389  if(!image_mod_.empty()) {
390  v.emplace_back("image_mod=" + image_mod_);
391  }
392 
393  if(!halo_.get_original().empty()) {
394  v.emplace_back("halo=" + halo_.get_original());
395  }
396 
397  if(!halo_x_.get_original().empty()) {
398  v.emplace_back("halo_x=" + halo_x_.get_original());
399  }
400 
401  if(!halo_y_.get_original().empty()) {
402  v.emplace_back("halo_y=" + halo_y_.get_original());
403  }
404 
405  if(!halo_mod_.empty()) {
406  v.emplace_back("halo_mod=" + halo_mod_);
407  }
408 
409  if(!sound_.empty()) {
410  v.emplace_back("sound=" + sound_);
411  }
412 
413  if(!text_.empty()) {
414  v.emplace_back("text=" + text_);
415 
416  if(text_color_) {
417  v.emplace_back("text_color=" + text_color_->to_rgba_string());
418  }
419  }
420 
421  if(!blend_ratio_.get_original().empty()) {
422  v.emplace_back("blend_ratio=" + blend_ratio_.get_original());
423 
424  if(blend_with_) {
425  v.emplace_back("blend_with=" + blend_with_->to_rgba_string());
426  }
427  }
428 
429  if(!highlight_ratio_.get_original().empty()) {
430  v.emplace_back("highlight_ratio=" + highlight_ratio_.get_original());
431  }
432 
433  if(!offset_.get_original().empty()) {
434  v.emplace_back("offset=" + offset_.get_original());
435  }
436 
437  if(!submerge_.get_original().empty()) {
438  v.emplace_back("submerge=" + submerge_.get_original());
439  }
440 
441  if(!x_.get_original().empty()) {
442  v.emplace_back("x=" + x_.get_original());
443  }
444 
445  if(!y_.get_original().empty()) {
446  v.emplace_back("y=" + y_.get_original());
447  }
448 
449  if(!directional_x_.get_original().empty()) {
450  v.emplace_back("directional_x=" + directional_x_.get_original());
451  }
452 
453  if(!directional_y_.get_original().empty()) {
454  v.emplace_back("directional_y=" + directional_y_.get_original());
455  }
456 
457  if(!boost::indeterminate(auto_vflip_)) {
458  v.emplace_back("auto_vflip=" + utils::bool_string(static_cast<bool>(auto_vflip_)));
459  }
460 
461  if(!boost::indeterminate(auto_hflip_)) {
462  v.emplace_back("auto_hflip=" + utils::bool_string(static_cast<bool>(auto_hflip_)));
463  }
464 
465  if(!boost::indeterminate(primary_frame_)) {
466  v.emplace_back("primary_frame=" + utils::bool_string(static_cast<bool>(primary_frame_)));
467  }
468 
469  if(!drawing_layer_.get_original().empty()) {
470  v.emplace_back("drawing_layer=" + drawing_layer_.get_original());
471  }
472 
473  return v;
474 }
475 
476 void unit_frame::redraw(const int frame_time, bool on_start_time, bool in_scope_of_frame,
477  const map_location& src, const map_location& dst,
478  halo::handle& halo_id, halo::manager& halo_man,
479  const frame_parameters& animation_val, const frame_parameters& engine_val) const
480 {
482 
483  const int xsrc = game_disp->get_location_x(src);
484  const int ysrc = game_disp->get_location_y(src);
485  const int xdst = game_disp->get_location_x(dst);
486  const int ydst = game_disp->get_location_y(dst);
487  const map_location::DIRECTION direction = src.get_relative_dir(dst);
488 
489  const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
490  double tmp_offset = current_data.offset;
491 
492  // Debug code to see the number of frames and their position
493  //if(tmp_offset) {
494  // std::cout << static_cast<int>(tmp_offset * 100) << "," << "\n";
495  //}
496 
497  if(on_start_time) {
498  // Stuff that should be done only once per frame
499  if(!current_data.sound.empty() ) {
500  sound::play_sound(current_data.sound);
501  }
502 
503  if(!current_data.text.empty() && current_data.text_color) {
504  game_disp->float_label(src, current_data.text, *current_data.text_color);
505  }
506  }
507 
508  image::locator image_loc;
509  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
510  image_loc = image::locator(current_data.image_diagonal, current_data.image_mod);
511  }
512 
513  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
514  image_loc = image::locator(current_data.image, current_data.image_mod);
515  }
516 
517  surface image;
518  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
519  image=image::get_image(image_loc, image::SCALED_TO_ZOOM);
520  }
521 
522  const int d2 = display::get_singleton()->hex_size() / 2;
523 
524  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc) + d2;
525  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc) + d2;
526  const double disp_zoom = display::get_singleton()->get_zoom_factor();
527 
528  if(image != nullptr) {
529  bool facing_west = (
530  direction == map_location::NORTH_WEST ||
531  direction == map_location::SOUTH_WEST);
532 
533  bool facing_north = (
534  direction == map_location::NORTH_WEST ||
535  direction == map_location::NORTH ||
536  direction == map_location::NORTH_EAST);
537 
538  if(!current_data.auto_hflip) { facing_west = false; }
539  if(!current_data.auto_vflip) { facing_north = true; }
540 
541  int my_x = x + current_data.x * disp_zoom - image->w / 2;
542  int my_y = y + current_data.y * disp_zoom - image->h / 2;
543 
544  if(facing_west) {
545  my_x -= current_data.directional_x * disp_zoom;
546  } else {
547  my_x += current_data.directional_x * disp_zoom;
548  }
549 
550  if(facing_north) {
551  my_y += current_data.directional_y * disp_zoom;
552  } else {
553  my_y -= current_data.directional_y * disp_zoom;
554  }
555 
556  display::get_singleton()->render_image(my_x, my_y,
557  static_cast<display::drawing_layer>(display::LAYER_UNIT_FIRST + current_data.drawing_layer),
558  src, image, facing_west, false,
559  ftofxp(current_data.highlight_ratio), current_data.blend_with ? *current_data.blend_with : color_t(),
560  current_data.blend_ratio, current_data.submerge, !facing_north);
561  }
562 
563  halo_id.reset();
564 
565  if(!in_scope_of_frame) { //check after frame as first/last frame image used in defense/attack anims
566  return;
567  }
568 
569  // No halos, exit
570  if(current_data.halo.empty()) {
571  return;
572  }
573 
574  halo::ORIENTATION orientation;
575  switch(direction)
576  {
577  case map_location::NORTH:
579  orientation = halo::NORMAL;
580  break;
582  case map_location::SOUTH:
583  if(!current_data.auto_vflip) {
584  orientation = halo::NORMAL;
585  } else {
586  orientation = halo::VREVERSE;
587  }
588  break;
590  if(!current_data.auto_vflip) {
591  orientation = halo::HREVERSE;
592  } else {
593  orientation = halo::HVREVERSE;
594  }
595  break;
597  orientation = halo::HREVERSE;
598  break;
600  default:
601  orientation = halo::NORMAL;
602  break;
603  }
604 
605  if(direction != map_location::SOUTH_WEST && direction != map_location::NORTH_WEST) {
606  halo_id = halo_man.add(
607  static_cast<int>(x + current_data.halo_x * disp_zoom),
608  static_cast<int>(y + current_data.halo_y * disp_zoom),
609  current_data.halo + current_data.halo_mod,
610  map_location(-1, -1),
611  orientation
612  );
613  } else {
614  halo_id = halo_man.add(
615  static_cast<int>(x - current_data.halo_x * disp_zoom),
616  static_cast<int>(y + current_data.halo_y * disp_zoom),
617  current_data.halo + current_data.halo_mod,
618  map_location(-1, -1),
619  orientation
620  );
621  }
622 }
623 
624 std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time, const map_location& src, const map_location& dst,
625  const frame_parameters& animation_val, const frame_parameters& engine_val) const
626 {
628 
629  const int xsrc = disp->get_location_x(src);
630  const int ysrc = disp->get_location_y(src);
631  const int xdst = disp->get_location_x(dst);
632  const int ydst = disp->get_location_y(dst);
633  const map_location::DIRECTION direction = src.get_relative_dir(dst);
634 
635  const frame_parameters current_data = merge_parameters(frame_time, animation_val, engine_val);
636 
637  double tmp_offset = current_data.offset;
638  const int d2 = display::get_singleton()->hex_size() / 2;
639 
640  image::locator image_loc;
641  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
642  image_loc = image::locator(current_data.image_diagonal, current_data.image_mod);
643  }
644 
645  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
646  image_loc = image::locator(current_data.image, current_data.image_mod);
647  }
648 
649  // We always invalidate our own hex because we need to be called at redraw time even
650  // if we don't draw anything in the hex itself
651  std::set<map_location> result;
652  if(tmp_offset == 0 && current_data.x == 0 && current_data.directional_x == 0 && image::is_in_hex(image_loc)) {
653  result.insert(src);
654 
655  bool facing_north = (
656  direction == map_location::NORTH_WEST ||
657  direction == map_location::NORTH ||
658  direction == map_location::NORTH_EAST);
659 
660  if(!current_data.auto_vflip) { facing_north = true; }
661 
662  int my_y = current_data.y;
663  if(facing_north) {
664  my_y += current_data.directional_y;
665  } else {
666  my_y -= current_data.directional_y;
667  }
668 
669  if(my_y < 0) {
670  result.insert(src.get_direction(map_location::NORTH));
671  result.insert(src.get_direction(map_location::NORTH_EAST));
672  result.insert(src.get_direction(map_location::NORTH_WEST));
673  } else if(my_y > 0) {
674  result.insert(src.get_direction(map_location::SOUTH));
675  result.insert(src.get_direction(map_location::SOUTH_EAST));
676  result.insert(src.get_direction(map_location::SOUTH_WEST));
677  }
678  } else {
679  int w = 0, h = 0;
680 
681  {
682  surface image;
683  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
684  image = image::get_image(image_loc, image::SCALED_TO_ZOOM);
685  }
686 
687  if(image != nullptr) {
688  w = image->w;
689  h = image->h;
690  }
691  }
692 
693  if(w != 0 || h != 0) {
694  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc);
695  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc);
696 
697  bool facing_west = (
698  direction == map_location::NORTH_WEST ||
699  direction == map_location::SOUTH_WEST);
700 
701  bool facing_north = (
702  direction == map_location::NORTH_WEST ||
703  direction == map_location::NORTH ||
704  direction == map_location::NORTH_EAST);
705 
706  if(!current_data.auto_vflip) { facing_north = true; }
707  if(!current_data.auto_hflip) { facing_west = false; }
708 
709  int my_x = x + current_data.x + d2 - w / 2;
710  int my_y = y + current_data.y + d2 - h / 2;
711 
712  if(facing_west) {
713  my_x += current_data.directional_x;
714  } else {
715  my_x -= current_data.directional_x;
716  }
717 
718  if(facing_north) {
719  my_y += current_data.directional_y;
720  } else {
721  my_y -= current_data.directional_y;
722  }
723 
724  // Check if our underlying hexes are invalidated. If we need to update ourselves because we changed,
725  // invalidate our hexes and return whether or not was successful.
726  const SDL_Rect r {my_x, my_y, w, h};
727  display::rect_of_hexes underlying_hex = disp->hexes_under_rect(r);
728 
729  result.insert(src);
730  result.insert(underlying_hex.begin(), underlying_hex.end());
731  } else {
732  // We have no "redraw surface" but we still need to invalidate our own hex in case we have a halo
733  // and/or sound that needs a redraw.
734  result.insert(src);
735  result.insert(dst);
736  }
737  }
738 
739  return result;
740 }
741 
742 /**
743  * This function merges the value provided by:
744  * - the frame
745  * - the engine (poison, flying unit...)
746  * - the animation as a whole
747  *
748  * There is no absolute rule for merging, so creativity is the rule. If a value is never provided by the engine, assert.
749  * This way if it becomes used, people will easily find the right place to look.
750  */
751 const frame_parameters unit_frame::merge_parameters(int current_time, const frame_parameters& animation_val,
752  const frame_parameters& engine_val) const
753 {
754  frame_parameters result;
755  const frame_parameters& current_val = builder_.parameters(current_time);
756 
757  result.primary_frame = engine_val.primary_frame;
758  if(!boost::logic::indeterminate(animation_val.primary_frame)) {
759  result.primary_frame = animation_val.primary_frame;
760  }
761 
762  if(!boost::logic::indeterminate(current_val.primary_frame)) {
763  result.primary_frame = current_val.primary_frame;
764  }
765 
766  // Convert the tribool to bool
767  const bool primary = static_cast<bool>(result.primary_frame) || boost::logic::indeterminate(result.primary_frame);
768 
769  /** The engine provides a default image to use for the unit when none is available */
770  result.image = current_val.image.is_void() || current_val.image.get_filename().empty()
771  ? animation_val.image
772  : current_val.image;
773 
774  if(primary && (result.image.is_void() || result.image.get_filename().empty())) {
775  result.image = engine_val.image;
776  }
777 
778  /** The engine provides a default image to use for the unit when none is available */
779  result.image_diagonal = current_val.image_diagonal.is_void() || current_val.image_diagonal.get_filename().empty()
780  ? animation_val.image_diagonal
781  : current_val.image_diagonal;
782 
783  if(primary && (result.image_diagonal.is_void() || result.image_diagonal.get_filename().empty())) {
784  result.image_diagonal = engine_val.image_diagonal;
785  }
786 
787  /**
788  * The engine provides a string for "petrified" and "team color" modifications.
789  * Note that image_mod is the complete modification and halo_mod is only the TC part.
790  */
791  result.image_mod = current_val.image_mod + animation_val.image_mod;
792  if(primary) {
793  result.image_mod += engine_val.image_mod;
794  } else {
795  result.image_mod += engine_val.halo_mod;
796  }
797 
798  assert(engine_val.halo.empty());
799  result.halo = current_val.halo.empty() ? animation_val.halo : current_val.halo;
800 
801  assert(engine_val.halo_x == 0);
802  result.halo_x = current_val.halo_x ? current_val.halo_x : animation_val.halo_x;
803 
804  /** The engine provides a y modification for terrain with height adjust and flying units */
805  result.halo_y = current_val.halo_y ? current_val.halo_y : animation_val.halo_y;
806  result.halo_y += engine_val.halo_y;
807 
808  result.halo_mod = current_val.halo_mod + animation_val.halo_mod;
809  result.halo_mod += engine_val.halo_mod;
810 
811  assert(engine_val.duration == 0);
812  result.duration = current_val.duration;
813 
814  assert(engine_val.sound.empty());
815  result.sound = current_val.sound.empty() ? animation_val.sound : current_val.sound;
816 
817  assert(engine_val.text.empty());
818  result.text = current_val.text.empty() ? animation_val.text : current_val.text;
819 
820  assert(!engine_val.text_color);
821  result.text_color = current_val.text_color ? current_val.text_color : animation_val.text_color;
822 
823  /** The engine provides a blend color for poisoned units */
824  result.blend_with = current_val.blend_with ? current_val.blend_with : animation_val.blend_with;
825  if(primary && engine_val.blend_with) {
826  result.blend_with = engine_val.blend_with->blend_lighten(result.blend_with ? *result.blend_with : color_t(0,0,0));
827  }
828 
829  /** The engine provides a blend color for poisoned units */
830  result.blend_ratio = current_val.blend_ratio != 0 ? current_val.blend_ratio:animation_val.blend_ratio;
831  if(primary && engine_val.blend_ratio != 0) {
832  result.blend_ratio = std::min(result.blend_ratio + engine_val.blend_ratio, 1.0);
833  }
834 
835  /** The engine provides a highlight ratio for selected units and visible "invisible" units */
836  result.highlight_ratio = (current_val.highlight_ratio < 0.999 || current_val.highlight_ratio > 1.001) ?
837  current_val.highlight_ratio : animation_val.highlight_ratio;
838  if(primary && (engine_val.highlight_ratio < 0.999 || engine_val.highlight_ratio > 1.001)) {
839  result.highlight_ratio = result.highlight_ratio * engine_val.highlight_ratio; // selected unit
840  }
841 
842  assert(engine_val.offset == 0);
843  result.offset = (current_val.offset != -1000) ? current_val.offset : animation_val.offset;
844  if(result.offset == -1000) {
845  result.offset = 0.0;
846  }
847 
848  /** The engine provides a submerge for units in water */
849  result.submerge = current_val.submerge != 0 ? current_val.submerge : animation_val.submerge;
850  if(primary && engine_val.submerge != 0 && result.submerge == 0) {
851  result.submerge = engine_val.submerge;
852  }
853 
854  assert(engine_val.x == 0);
855  result.x = current_val.x ? current_val.x : animation_val.x;
856 
857  /** The engine provides a y modification for terrain with height adjust and flying units */
858  result.y = current_val.y?current_val.y:animation_val.y;
859  result.y += engine_val.y;
860 
861  assert(engine_val.directional_x == 0);
862  result.directional_x = current_val.directional_x ? current_val.directional_x : animation_val.directional_x;
863 
864  assert(engine_val.directional_y == 0);
865  result.directional_y = current_val.directional_y ? current_val.directional_y : animation_val.directional_y;
866 
869  ? current_val.drawing_layer
870  : animation_val.drawing_layer;
871 
872  /** The engine provides us with a default value to compare to. Update if different */
873  result.auto_hflip = engine_val.auto_hflip;
874 
875  if(!boost::logic::indeterminate(animation_val.auto_hflip)) {
876  result.auto_hflip = animation_val.auto_hflip;
877  }
878 
879  if(!boost::logic::indeterminate(current_val.auto_hflip)) {
880  result.auto_hflip = current_val.auto_hflip;
881  }
882 
883  if(boost::logic::indeterminate(result.auto_hflip)) {
884  result.auto_hflip = true;
885  }
886 
887  result.auto_vflip = engine_val.auto_vflip;
888 
889  if(!boost::logic::indeterminate(animation_val.auto_vflip)) {
890  result.auto_vflip = animation_val.auto_vflip;
891  }
892 
893  if(!boost::logic::indeterminate(current_val.auto_vflip)) {
894  result.auto_vflip = current_val.auto_vflip;
895  }
896 
897  if(boost::logic::indeterminate(result.auto_vflip)) {
898  result.auto_vflip = !primary;
899  }
900 
901  return result;
902 }
const frame_parameters parameters(int current_time) const
Getters for the different parameters.
Definition: frame.cpp:291
virtual bool does_not_change() const
surface get_image(const image::locator &i_locator, TYPE type)
Caches and returns an image.
Definition: picture.cpp:816
virtual const T get_current_element(int current_time, T default_val=T()) const override
Reserve layers to be selected for WML.
Definition: display.hpp:833
std::set< map_location > get_overlaped_hex(const int frame_time, const map_location &src, const map_location &dst, const frame_parameters &animation_val, const frame_parameters &engine_val) const
Definition: frame.cpp:624
std::string image_
Definition: frame.hpp:109
frame_builder & y(const std::string &y)
Definition: frame.cpp:198
std::string sound
Definition: frame.hpp:51
boost::tribool auto_hflip_
Definition: frame.hpp:194
All parameters from a frame at a given instant.
Definition: frame.hpp:35
boost::tribool auto_hflip
Definition: frame.hpp:68
image::locator image
Definition: frame.hpp:41
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:92
progressive_int halo_x_
Definition: frame.hpp:174
progressive_single< image::locator > progressive_image
progressive_double blend_ratio_
Definition: frame.hpp:184
frame_parsed_parameters(const frame_builder &builder=frame_builder(), int override_duration=0)
Definition: frame.cpp:240
frame_builder & blend(const std::string &blend_ratio, const color_t blend_color)
Definition: frame.cpp:167
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:227
static int hex_size()
Function which returns the size of a hex in pixels (from top tip to bottom tip or left edge to right ...
Definition: display.hpp:260
std::optional< color_t > blend_with
Definition: frame.hpp:55
std::string image_mod_
Definition: frame.hpp:171
std::string blend_ratio_
Definition: frame.hpp:122
std::string sound_
Definition: frame.hpp:178
Variant for storing WML attributes.
std::string directional_y_
Definition: frame.hpp:129
static double get_zoom_factor()
Returns the current zoom factor.
Definition: display.hpp:263
std::string text_
Definition: frame.hpp:117
bool has_attribute(config_key_type key) const
Definition: config.cpp:211
Frame for unit&#39;s animation sequence.
frame_builder()
Definition: frame.cpp:44
void render_image(int x, int y, const display::drawing_layer drawing_layer, const map_location &loc, surface image, bool hreverse=false, bool greyscale=false, fixed_t alpha=ftofxp(1.0), color_t blendto={0, 0, 0}, double blend_ratio=0, double submerged=0.0, bool vreverse=false)
Draw an image at a certain location.
Definition: display.cpp:1552
int directional_x
Definition: frame.hpp:64
frame_builder & drawing_layer(const std::string &drawing_layer)
Definition: frame.cpp:234
frame_builder & image_diagonal(const std::string &image_diagonal, const std::string &image_mod="")
Definition: frame.cpp:132
int drawing_layer
Definition: frame.hpp:71
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:780
std::string drawing_layer_
Definition: frame.hpp:135
std::string get_original() const
STL namespace.
#define h
std::string text
Definition: frame.hpp:52
Audio output for sound and music.
Definition: sound.cpp:41
std::string halo_mod_
Definition: frame.hpp:115
int directional_y
Definition: frame.hpp:65
Rectangular area of hexes, allowing to decide how the top and bottom edges handles the vertical shift...
Definition: display.hpp:306
frame_builder & directional_x(const std::string &directional_x)
Definition: frame.cpp:204
std::string halo_y_
Definition: frame.hpp:114
void override(int 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:321
frame_builder & image(const std::string &image, const std::string &image_mod="")
Definition: frame.cpp:125
image::locator image_diagonal
Definition: frame.hpp:42
boost::tribool primary_frame_
Definition: frame.hpp:133
std::string halo
Definition: frame.hpp:45
std::string halo_
Definition: frame.hpp:112
iterator begin() const
Definition: display.cpp:679
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Definition: sound.cpp:1021
map_location get_direction(DIRECTION dir, unsigned int n=1u) const
Definition: location.cpp:360
frame_builder & submerge(const std::string &submerge)
Definition: frame.cpp:186
bool does_not_change() const override
virtual const T get_current_element(int current_time, T default_val=T()) const override
frame_builder & auto_hflip(const bool auto_hflip)
Definition: frame.cpp:222
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
std::optional< color_t > blend_with_
Definition: frame.hpp:182
frame_builder & sound(const std::string &sound)
Definition: frame.cpp:139
std::string halo_mod
Definition: frame.hpp:50
progressive_image image_diagonal_
Definition: frame.hpp:169
std::string highlight_ratio_
Definition: frame.hpp:123
progressive_int x_
Definition: frame.hpp:188
boost::tribool primary_frame_
Definition: frame.hpp:195
std::string text_
Definition: frame.hpp:179
frame_builder & auto_vflip(const bool auto_vflip)
Definition: frame.cpp:216
progressive_image image_
Definition: frame.hpp:168
progressive_double highlight_ratio_
Definition: frame.hpp:185
std::string y_
Definition: frame.hpp:127
progressive_int halo_y_
Definition: frame.hpp:175
progressive_pair< int > progressive_int
std::optional< color_t > text_color
Definition: frame.hpp:54
const rect_of_hexes hexes_under_rect(const SDL_Rect &r) const
Return the rectangular area of hexes overlapped by r (r is in screen coordinates) ...
Definition: display.cpp:688
std::string directional_x_
Definition: frame.hpp:128
Generic locator abstracting the location of an image.
Definition: picture.hpp:60
progressive_int drawing_layer_
Definition: frame.hpp:197
std::vector< std::string > debug_strings() const
Contents of frame in strings.
Definition: frame.cpp:373
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:453
#define ftofxp(x)
IN: float or int - OUT: fixed_t.
Definition: math.hpp:318
Image rescaled according to the zoom settings.
Definition: picture.hpp:234
progressive_int directional_x_
Definition: frame.hpp:190
Encapsulates the map of the game.
Definition: location.hpp:38
void float_label(const map_location &loc, const std::string &text, const color_t &color)
Function to float a label above a tile.
std::optional< color_t > text_color_
Definition: frame.hpp:181
progressive_single< std::string > progressive_string
std::optional< color_t > text_color_
Definition: frame.hpp:119
void redraw(const int 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:476
static lg::log_domain log_engine("engine")
double highlight_ratio
Definition: frame.hpp:58
int duration() const
Definition: frame.hpp:158
default layer for drawing units
Definition: display.hpp:835
std::string image_mod
Definition: frame.hpp:44
int get_location_y(const map_location &loc) const
Definition: display.cpp:755
int duration_
Definition: frame.hpp:107
std::string bool_string(const bool value)
Converts a bool value to &#39;true&#39; or &#39;false&#39;.
frame_builder & offset(const std::string &offset)
Definition: frame.cpp:180
bool need_update() const
Definition: frame.cpp:286
frame_builder & x(const std::string &x)
Definition: frame.cpp:192
std::string offset_
Definition: frame.hpp:124
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
boost::tribool auto_vflip
Definition: frame.hpp:67
int w
const std::string & get_filename() const
Definition: picture.hpp:78
frame_builder & primary_frame(const bool primary_frame)
Definition: frame.cpp:228
bool is_in_hex(const locator &i_locator)
Checks if an image fits into a single hex.
Definition: picture.cpp:947
frame_builder & directional_y(const std::string &directional_y)
Definition: frame.cpp:210
double blend_ratio
Definition: frame.hpp:57
progressive_double submerge_
Definition: frame.hpp:187
double submerge
Definition: frame.hpp:60
double offset
Definition: frame.hpp:59
Definition: display.hpp:45
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:750
#define ERR_NG
Definition: frame.cpp:24
ORIENTATION
Definition: halo.hpp:34
iterator end() const
Definition: display.cpp:683
progressive_int directional_y_
Definition: frame.hpp:191
std::optional< color_t > blend_with_
Definition: frame.hpp:120
boost::tribool auto_vflip_
Definition: frame.hpp:131
Functions to load and save images from/to disk.
Standard logging facilities (interface).
std::string halo_mod_
Definition: frame.hpp:177
frame_builder & duration(const int duration)
Allow easy chained modifications.
Definition: frame.cpp:161
std::string image_diagonal_
Definition: frame.hpp:110
boost::tribool auto_hflip_
Definition: frame.hpp:132
progressive_double offset_
Definition: frame.hpp:186
#define e
frame_builder & highlight(const std::string &highlight)
Definition: frame.cpp:174
std::string halo_x_
Definition: frame.hpp:113
std::string x_
Definition: frame.hpp:126
bool is_void() const
Returns true if the locator does not correspond to an actual image.
Definition: picture.hpp:90
progressive_string halo_
Definition: frame.hpp:173
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
progressive_int y_
Definition: frame.hpp:189
std::string image_mod_
Definition: frame.hpp:111
std::shared_ptr< halo_record > handle
Definition: halo.hpp:30
boost::tribool primary_frame
Definition: frame.hpp:69
frame_builder & text(const std::string &text, const color_t text_color)
Definition: frame.cpp:145
static color_t from_rgb_string(const std::string &c)
Creates a new opaque color_t object from a string variable in "R,G,B" format.
Definition: color.cpp:42
bool does_not_change() const
Definition: frame.cpp:267
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:152
const frame_parameters merge_parameters(int 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:751
progressive_pair< double > progressive_double
static game_display * get_singleton()
std::string submerge_
Definition: frame.hpp:125
std::string sound_
Definition: frame.hpp:116
boost::tribool auto_vflip_
Definition: frame.hpp:193