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