The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 http://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_ = boost::logic::indeterminate;
77  } else {
78  auto_vflip_ = cfg[frame_string + "auto_vflip"].to_bool();
79  }
80 
81  if(!cfg.has_attribute(frame_string + "auto_hflip")) {
82  auto_hflip_ = boost::logic::indeterminate;
83  } else {
84  auto_hflip_ = cfg[frame_string + "auto_hflip"].to_bool();
85  }
86 
87  if(!cfg.has_attribute(frame_string + "primary")) {
88  primary_frame_ = boost::logic::indeterminate;
89  } else {
90  primary_frame_ = cfg[frame_string + "primary"].to_bool();
91  }
92 
93  std::vector<std::string> color = utils::split(cfg[frame_string + "text_color"]);
94  if(color.size() == 3) {
95  try {
96  text_color_ = color_t(std::stoi(color[0]), std::stoi(color[1]), std::stoi(color[2]));
97  } catch(std::invalid_argument&) {
98  ERR_NG << "Invalid RGB color value in unit animation: " << color[0] << ", " << color[1] << ", " << color[2] << "\n";
99  }
100  }
101 
102  if(const config::attribute_value* v = cfg.get(frame_string + "duration")) {
103  duration(*v);
104  } else if(!cfg.get(frame_string + "end")) {
105  int halo_duration = (progressive_string(halo_, 1)).duration();
106  int image_duration = (progressive_image(image_, 1)).duration();
107  int image_diagonal_duration = (progressive_image(image_diagonal_, 1)).duration();
108 
109  duration(std::max(std::max(image_duration, image_diagonal_duration), halo_duration));
110  } else {
111  duration(cfg[frame_string + "end"].to_int() - cfg[frame_string + "begin"].to_int());
112  }
113 
114  duration_ = std::max(duration_, 1);
115 
116  color = utils::split(cfg[frame_string + "blend_color"]);
117  if(color.size() == 3) {
118  try {
119  blend_with_ = color_t(std::stoi(color[0]), std::stoi(color[1]), std::stoi(color[2]));
120  } catch(std::invalid_argument&) {
121  ERR_NG << "Invalid RGB color value in unit animation: " << color[0] << ", " << color[1] << ", " << color[2] << "\n";
122  }
123  }
124 }
125 
127 {
128  image_ = image;
129  image_mod_ = image_mod;
130  return *this;
131 }
132 
133 frame_builder& frame_builder::image_diagonal(const std::string& image_diagonal,const std::string& image_mod)
134 {
136  image_mod_ = image_mod;
137  return *this;
138 }
139 
141 {
142  sound_ = sound;
143  return *this;
144 }
145 
146 frame_builder& frame_builder::text(const std::string& text,const color_t text_color)
147 {
148  text_ = text;
149  text_color_ = text_color;
150  return *this;
151 }
152 
153 frame_builder& frame_builder::halo(const std::string& halo, const std::string& halo_x, const std::string& halo_y,const std::string& halo_mod)
154 {
155  halo_ = halo;
156  halo_x_ = halo_x;
157  halo_y_ = halo_y;
158  halo_mod_= halo_mod;
159  return *this;
160 }
161 
163 {
165  return *this;
166 }
167 
168 frame_builder& frame_builder::blend(const std::string& blend_ratio,const color_t blend_color)
169 {
170  blend_with_ = blend_color;
171  blend_ratio_ = blend_ratio;
172  return *this;
173 }
174 
176 {
178  return *this;
179 }
180 
182 {
183  offset_ = offset;
184  return *this;
185 }
186 
188 {
190  return *this;
191 }
192 
194 {
195  x_ = x;
196  return *this;
197 }
198 
200 {
201  y_ = y;
202  return *this;
203 }
204 
206 {
208  return *this;
209 }
210 
212 {
214  return *this;
215 }
216 
218 {
220  return *this;
221 }
222 
224 {
226  return *this;
227 }
228 
229 frame_builder& frame_builder::primary_frame(const bool primary_frame)
230 {
232  return *this;
233 }
234 
236 {
238  return *this;
239 }
240 
242  : duration_(duration ? duration : builder.duration_)
243  , image_(builder.image_,duration_)
244  , image_diagonal_(builder.image_diagonal_,duration_)
245  , image_mod_(builder.image_mod_)
246  , halo_(builder.halo_,duration_)
247  , halo_x_(builder.halo_x_,duration_)
248  , halo_y_(builder.halo_y_,duration_)
249  , halo_mod_(builder.halo_mod_)
250  , sound_(builder.sound_)
251  , text_(builder.text_)
252  , text_color_(builder.text_color_)
253  , blend_with_(builder.blend_with_)
254  , blend_ratio_(builder.blend_ratio_,duration_)
255  , highlight_ratio_(builder.highlight_ratio_,duration_)
256  , offset_(builder.offset_,duration_)
257  , submerge_(builder.submerge_,duration_)
258  , x_(builder.x_,duration_)
259  , y_(builder.y_,duration_)
260  , directional_x_(builder.directional_x_,duration_)
261  , directional_y_(builder.directional_y_,duration_)
262  , auto_vflip_(builder.auto_vflip_)
263  , auto_hflip_(builder.auto_hflip_)
264  , primary_frame_(builder.primary_frame_)
265  , drawing_layer_(builder.drawing_layer_,duration_)
266 {}
267 
269 {
270  return
280  x_.does_not_change() &&
281  y_.does_not_change() &&
285 }
286 
288 {
289  return !this->does_not_change();
290 }
291 
293 {
294  frame_parameters result;
295  result.duration = duration_;
296  result.image = image_.get_current_element(current_time);
297  result.image_diagonal = image_diagonal_.get_current_element(current_time);
298  result.image_mod = image_mod_;
299  result.halo = halo_.get_current_element(current_time);
300  result.halo_x = halo_x_.get_current_element(current_time);
301  result.halo_y = halo_y_.get_current_element(current_time);
302  result.halo_mod = halo_mod_;
303  result.sound = sound_;
304  result.text = text_;
305  result.text_color = text_color_;
306  result.blend_with = blend_with_;
307  result.blend_ratio = blend_ratio_.get_current_element(current_time);
308  result.highlight_ratio = highlight_ratio_.get_current_element(current_time,1.0);
309  result.offset = offset_.get_current_element(current_time,-1000);
310  result.submerge = submerge_.get_current_element(current_time);
311  result.x = x_.get_current_element(current_time);
312  result.y = y_.get_current_element(current_time);
313  result.directional_x = directional_x_.get_current_element(current_time);
314  result.directional_y = directional_y_.get_current_element(current_time);
315  result.auto_vflip = auto_vflip_;
316  result.auto_hflip = auto_hflip_;
317  result.primary_frame = primary_frame_;
319  return result;
320 }
321 
323  const std::string& highlight,
324  const std::string& blend_ratio,
325  color_t blend_color,
326  const std::string& offset,
327  const std::string& layer,
328  const std::string& modifiers)
329 {
330  if(!highlight.empty()) {
331  highlight_ratio_ = progressive_double(highlight,duration);
332  } else if(duration != duration_){
334  }
335 
336  if(!offset.empty()) {
337  offset_ = progressive_double(offset,duration);
338  } else if(duration != duration_){
340  }
341 
342  if(!blend_ratio.empty()) {
343  blend_ratio_ = progressive_double(blend_ratio,duration);
344  blend_with_ = blend_color;
345  } else if(duration != duration_){
347  }
348 
349  if(!layer.empty()) {
350  drawing_layer_ = progressive_int(layer,duration);
351  } else if(duration != duration_){
353  }
354 
355  if(!modifiers.empty()) {
356  image_mod_ += modifiers;
357  }
358 
359  if(duration != duration_) {
371  }
372 }
373 
374 std::vector<std::string> frame_parsed_parameters::debug_strings() const
375 {
376  std::vector<std::string> v;
377 
378  if(duration_ > 0) {
379  v.emplace_back("duration=" + utils::half_signed_value(duration_));
380  }
381 
382  if(!image_.get_original().empty()) {
383  v.emplace_back("image=" + image_.get_original());
384  }
385 
386  if(!image_diagonal_.get_original().empty()) {
387  v.emplace_back("image_diagonal=" + image_diagonal_.get_original());
388  }
389 
390  if(!image_mod_.empty()) {
391  v.emplace_back("image_mod=" + image_mod_);
392  }
393 
394  if(!halo_.get_original().empty()) {
395  v.emplace_back("halo=" + halo_.get_original());
396  }
397 
398  if(!halo_x_.get_original().empty()) {
399  v.emplace_back("halo_x=" + halo_x_.get_original());
400  }
401 
402  if(!halo_y_.get_original().empty()) {
403  v.emplace_back("halo_y=" + halo_y_.get_original());
404  }
405 
406  if(!halo_mod_.empty()) {
407  v.emplace_back("halo_mod=" + halo_mod_);
408  }
409 
410  if(!sound_.empty()) {
411  v.emplace_back("sound=" + sound_);
412  }
413 
414  if(!text_.empty()) {
415  v.emplace_back("text=" + text_);
416 
417  if(text_color_) {
418  v.emplace_back("text_color=" + text_color_->to_rgba_string());
419  }
420  }
421 
422  if(!blend_ratio_.get_original().empty()) {
423  v.emplace_back("blend_ratio=" + blend_ratio_.get_original());
424 
425  if(blend_with_) {
426  v.emplace_back("blend_with=" + blend_with_->to_rgba_string());
427  }
428  }
429 
430  if(!highlight_ratio_.get_original().empty()) {
431  v.emplace_back("highlight_ratio=" + highlight_ratio_.get_original());
432  }
433 
434  if(!offset_.get_original().empty()) {
435  v.emplace_back("offset=" + offset_.get_original());
436  }
437 
438  if(!submerge_.get_original().empty()) {
439  v.emplace_back("submerge=" + submerge_.get_original());
440  }
441 
442  if(!x_.get_original().empty()) {
443  v.emplace_back("x=" + x_.get_original());
444  }
445 
446  if(!y_.get_original().empty()) {
447  v.emplace_back("y=" + y_.get_original());
448  }
449 
450  if(!directional_x_.get_original().empty()) {
451  v.emplace_back("directional_x=" + directional_x_.get_original());
452  }
453 
454  if(!directional_y_.get_original().empty()) {
455  v.emplace_back("directional_y=" + directional_y_.get_original());
456  }
457 
458  if(!boost::indeterminate(auto_vflip_)) {
459  v.emplace_back("auto_vflip=" + utils::bool_string(auto_vflip_));
460  }
461 
462  if(!boost::indeterminate(auto_hflip_)) {
463  v.emplace_back("auto_hflip=" + utils::bool_string(auto_hflip_));
464  }
465 
466  if(!boost::indeterminate(primary_frame_)) {
467  v.emplace_back("primary_frame=" + utils::bool_string(primary_frame_));
468  }
469 
470  if(!drawing_layer_.get_original().empty()) {
471  v.emplace_back("drawing_layer=" + drawing_layer_.get_original());
472  }
473 
474  return v;
475 }
476 
477 void unit_frame::redraw(const int frame_time, bool on_start_time, bool in_scope_of_frame,
478  const map_location& src, const map_location& dst,
479  halo::handle& halo_id, halo::manager& halo_man,
480  const frame_parameters& animation_val, const frame_parameters& engine_val) const
481 {
483 
484  const int xsrc = game_disp->get_location_x(src);
485  const int ysrc = game_disp->get_location_y(src);
486  const int xdst = game_disp->get_location_x(dst);
487  const int ydst = game_disp->get_location_y(dst);
488  const map_location::DIRECTION direction = src.get_relative_dir(dst);
489 
490  const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
491  double tmp_offset = current_data.offset;
492 
493  // Debug code to see the number of frames and their position
494  //if(tmp_offset) {
495  // std::cout << static_cast<int>(tmp_offset * 100) << "," << "\n";
496  //}
497 
498  if(on_start_time) {
499  // Stuff that should be done only once per frame
500  if(!current_data.sound.empty() ) {
501  sound::play_sound(current_data.sound);
502  }
503 
504  if(!current_data.text.empty() && current_data.text_color) {
505  game_disp->float_label(src, current_data.text, *current_data.text_color);
506  }
507  }
508 
509  image::locator image_loc;
510  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
511  image_loc = image::locator(current_data.image_diagonal, current_data.image_mod);
512  }
513 
514  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
515  image_loc = image::locator(current_data.image, current_data.image_mod);
516  }
517 
518  surface image;
519  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
520  image=image::get_image(image_loc, image::SCALED_TO_ZOOM);
521  }
522 
523  const int d2 = display::get_singleton()->hex_size() / 2;
524 
525  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc) + d2;
526  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc) + d2;
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 - image->w / 2;
542  int my_y = y + current_data.y - image->h / 2;
543 
544  if(facing_west) {
545  my_x -= current_data.directional_x;
546  } else {
547  my_x += current_data.directional_x;
548  }
549 
550  if(facing_north) {
551  my_y += current_data.directional_y;
552  } else {
553  my_y -= current_data.directional_y;
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 * display::get_singleton()->get_zoom_factor()),
608  static_cast<int>(y + current_data.halo_y * display::get_singleton()->get_zoom_factor()),
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 * display::get_singleton()->get_zoom_factor()),
616  static_cast<int>(y + current_data.halo_y * display::get_singleton()->get_zoom_factor()),
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 #ifdef _OPENMP
682 #pragma omp critical(frame_surface) // with the way surfaces work it's hard to lock the refcount within sdl_utils
683 #endif //_OPENMP
684 
685  {
686  surface image;
687  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
688  image = image::get_image(image_loc, image::SCALED_TO_ZOOM);
689  }
690 
691  if(image != nullptr) {
692  w = image->w;
693  h = image->h;
694  }
695  }
696 
697  if(w != 0 || h != 0) {
698  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc);
699  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc);
700 
701  bool facing_west = (
702  direction == map_location::NORTH_WEST ||
703  direction == map_location::SOUTH_WEST);
704 
705  bool facing_north = (
706  direction == map_location::NORTH_WEST ||
707  direction == map_location::NORTH ||
708  direction == map_location::NORTH_EAST);
709 
710  if(!current_data.auto_vflip) { facing_north = true; }
711  if(!current_data.auto_hflip) { facing_west = false; }
712 
713  int my_x = x + current_data.x + d2 - w / 2;
714  int my_y = y + current_data.y + d2 - h / 2;
715 
716  if(facing_west) {
717  my_x += current_data.directional_x;
718  } else {
719  my_x -= current_data.directional_x;
720  }
721 
722  if(facing_north) {
723  my_y += current_data.directional_y;
724  } else {
725  my_y -= current_data.directional_y;
726  }
727 
728  // Check if our underlying hexes are invalidated. If we need to update ourselves because we changed,
729  // invalidate our hexes and return whether or not was successful.
730  const SDL_Rect r {my_x, my_y, w, h};
731  display::rect_of_hexes underlying_hex = disp->hexes_under_rect(r);
732 
733  result.insert(src);
734  result.insert(underlying_hex.begin(), underlying_hex.end());
735  } else {
736  // We have no "redraw surface" but we still need to invalidate our own hex in case we have a halo
737  // and/or sound that needs a redraw.
738  result.insert(src);
739  result.insert(dst);
740  }
741  }
742 
743  return result;
744 }
745 
746 /**
747  * This function merges the value provided by:
748  * - the frame
749  * - the engine (poison, flying unit...)
750  * - the animation as a whole
751  *
752  * There is no absolute rule for merging, so creativity is the rule. If a value is never provided by the engine, assert.
753  * This way if it becomes used, people will easily find the right place to look.
754  */
755 const frame_parameters unit_frame::merge_parameters(int current_time, const frame_parameters& animation_val,
756  const frame_parameters& engine_val) const
757 {
758  frame_parameters result;
759  const frame_parameters& current_val = builder_.parameters(current_time);
760 
761  result.primary_frame = engine_val.primary_frame;
762  if(!boost::logic::indeterminate(animation_val.primary_frame)) {
763  result.primary_frame = animation_val.primary_frame;
764  }
765 
766  if(!boost::logic::indeterminate(current_val.primary_frame)) {
767  result.primary_frame = current_val.primary_frame;
768  }
769 
770  // Convert the tribool to bool
771  const bool primary = result.primary_frame == true || boost::logic::indeterminate(result.primary_frame);
772 
773  /** The engine provides a default image to use for the unit when none is available */
774  result.image = current_val.image.is_void() || current_val.image.get_filename().empty()
775  ? animation_val.image
776  : current_val.image;
777 
778  if(primary && (result.image.is_void() || result.image.get_filename().empty())) {
779  result.image = engine_val.image;
780  }
781 
782  /** The engine provides a default image to use for the unit when none is available */
783  result.image_diagonal = current_val.image_diagonal.is_void() || current_val.image_diagonal.get_filename().empty()
784  ? animation_val.image_diagonal
785  : current_val.image_diagonal;
786 
787  if(primary && (result.image_diagonal.is_void() || result.image_diagonal.get_filename().empty())) {
788  result.image_diagonal = engine_val.image_diagonal;
789  }
790 
791  /**
792  * The engine provides a string for "petrified" and "team color" modifications.
793  * Note that image_mod is the complete modification and halo_mod is only the TC part.
794  */
795  result.image_mod = current_val.image_mod + animation_val.image_mod;
796  if(primary) {
797  result.image_mod += engine_val.image_mod;
798  } else {
799  result.image_mod += engine_val.halo_mod;
800  }
801 
802  assert(engine_val.halo.empty());
803  result.halo = current_val.halo.empty() ? animation_val.halo : current_val.halo;
804 
805  assert(engine_val.halo_x == 0);
806  result.halo_x = current_val.halo_x ? current_val.halo_x : animation_val.halo_x;
807 
808  /** The engine provides a y modification for terrain with height adjust and flying units */
809  result.halo_y = current_val.halo_y ? current_val.halo_y : animation_val.halo_y;
810  result.halo_y += engine_val.halo_y;
811 
812  result.halo_mod = current_val.halo_mod + animation_val.halo_mod;
813  result.halo_mod += engine_val.halo_mod;
814 
815  assert(engine_val.duration == 0);
816  result.duration = current_val.duration;
817 
818  assert(engine_val.sound.empty());
819  result.sound = current_val.sound.empty() ? animation_val.sound : current_val.sound;
820 
821  assert(engine_val.text.empty());
822  result.text = current_val.text.empty() ? animation_val.text : current_val.text;
823 
824  assert(!engine_val.text_color);
825  result.text_color = current_val.text_color ? current_val.text_color : animation_val.text_color;
826 
827  /** The engine provides a blend color for poisoned units */
828  result.blend_with = current_val.blend_with ? current_val.blend_with : animation_val.blend_with;
829  if(primary && engine_val.blend_with) {
830  result.blend_with = engine_val.blend_with->blend_lighten(result.blend_with ? *result.blend_with : color_t(0,0,0));
831  }
832 
833  /** The engine provides a blend color for poisoned units */
834  result.blend_ratio = current_val.blend_ratio?current_val.blend_ratio:animation_val.blend_ratio;
835  if(primary && engine_val.blend_ratio) {
836  result.blend_ratio = std::min(result.blend_ratio + engine_val.blend_ratio, 1.0);
837  }
838 
839  /** The engine provides a highlight ratio for selected units and visible "invisible" units */
840  result.highlight_ratio = (current_val.highlight_ratio < 0.999 || current_val.highlight_ratio > 1.001) ?
841  current_val.highlight_ratio : animation_val.highlight_ratio;
842  if(primary && (engine_val.highlight_ratio < 0.999 || engine_val.highlight_ratio > 1.001)) {
843  result.highlight_ratio = result.highlight_ratio * engine_val.highlight_ratio; // selected unit
844  }
845 
846  assert(engine_val.offset == 0);
847  result.offset = (current_val.offset != -1000) ? current_val.offset : animation_val.offset;
848  if(result.offset == -1000) {
849  result.offset = 0.0;
850  }
851 
852  /** The engine provides a submerge for units in water */
853  result.submerge = current_val.submerge ? current_val.submerge : animation_val.submerge;
854  if(primary && engine_val.submerge && !result.submerge) {
855  result.submerge = engine_val.submerge;
856  }
857 
858  assert(engine_val.x == 0);
859  result.x = current_val.x ? current_val.x : animation_val.x;
860 
861  /** The engine provides a y modification for terrain with height adjust and flying units */
862  result.y = current_val.y?current_val.y:animation_val.y;
863  result.y += engine_val.y;
864 
865  assert(engine_val.directional_x == 0);
866  result.directional_x = current_val.directional_x ? current_val.directional_x : animation_val.directional_x;
867 
868  assert(engine_val.directional_y == 0);
869  result.directional_y = current_val.directional_y ? current_val.directional_y : animation_val.directional_y;
870 
873  ? current_val.drawing_layer
874  : animation_val.drawing_layer;
875 
876  /** The engine provides us with a default value to compare to. Update if different */
877  result.auto_hflip = engine_val.auto_hflip;
878 
879  if(!boost::logic::indeterminate(animation_val.auto_hflip)) {
880  result.auto_hflip = animation_val.auto_hflip;
881  }
882 
883  if(!boost::logic::indeterminate(current_val.auto_hflip)) {
884  result.auto_hflip = current_val.auto_hflip;
885  }
886 
887  if(boost::logic::indeterminate(result.auto_hflip)) {
888  result.auto_hflip = true;
889  }
890 
891  result.auto_vflip = engine_val.auto_vflip;
892 
893  if(!boost::logic::indeterminate(animation_val.auto_vflip)) {
894  result.auto_vflip = animation_val.auto_vflip;
895  }
896 
897  if(!boost::logic::indeterminate(current_val.auto_vflip)) {
898  result.auto_vflip = current_val.auto_vflip;
899  }
900 
901  if(boost::logic::indeterminate(result.auto_vflip)) {
902  result.auto_vflip = !primary;
903  }
904 
905  return result;
906 }
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:920
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:820
std::string image_
Definition: frame.hpp:107
frame_builder & y(const std::string &y)
Definition: frame.cpp:199
std::string sound
Definition: frame.hpp:49
boost::tribool auto_hflip_
Definition: frame.hpp:192
All parameters from a frame at a given instant.
Definition: frame.hpp:33
std::vector< char_t > string
boost::tribool auto_hflip
Definition: frame.hpp:66
image::locator image
Definition: frame.hpp:39
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:87
progressive_int halo_x_
Definition: frame.hpp:172
progressive_single< image::locator > progressive_image
bool is_void() const
Definition: image.hpp:95
progressive_double blend_ratio_
Definition: frame.hpp:182
frame_parsed_parameters(const frame_builder &builder=frame_builder(), int override_duration=0)
Definition: frame.cpp:241
frame_builder & blend(const std::string &blend_ratio, const color_t blend_color)
Definition: frame.cpp:168
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:254
iterator end() const
Definition: display.cpp:664
std::string image_mod_
Definition: frame.hpp:169
std::string blend_ratio_
Definition: frame.hpp:120
std::string sound_
Definition: frame.hpp:176
Variant for storing WML attributes.
std::string directional_y_
Definition: frame.hpp:127
static double get_zoom_factor()
Returns the current zoom factor.
Definition: display.hpp:257
std::vector< std::string > debug_strings() const
Contents of frame in strings.
Definition: frame.cpp:374
std::string text_
Definition: frame.hpp:115
boost::optional< color_t > text_color
Definition: frame.hpp:52
Frame for unit'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:1557
int directional_x
Definition: frame.hpp:62
virtual bool does_not_change() const
frame_builder & drawing_layer(const std::string &drawing_layer)
Definition: frame.cpp:235
frame_builder & image_diagonal(const std::string &image_diagonal, const std::string &image_mod="")
Definition: frame.cpp:133
int drawing_layer
Definition: frame.hpp:69
std::string drawing_layer_
Definition: frame.hpp:133
STL namespace.
#define h
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:225
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:731
std::string text
Definition: frame.hpp:50
Audio output for sound and music.
Definition: sound.cpp:40
std::string halo_mod_
Definition: frame.hpp:113
int directional_y
Definition: frame.hpp:63
Rectangular area of hexes, allowing to decide how the top and bottom edges handles the vertical shift...
Definition: display.hpp:297
frame_builder & directional_x(const std::string &directional_x)
Definition: frame.cpp:205
bool need_update() const
Definition: frame.cpp:287
std::string halo_y_
Definition: frame.hpp:112
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:322
frame_builder & image(const std::string &image, const std::string &image_mod="")
Definition: frame.cpp:126
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
image::locator image_diagonal
Definition: frame.hpp:40
const frame_parameters parameters(int current_time) const
Getters for the different parameters.
Definition: frame.cpp:292
boost::tribool primary_frame_
Definition: frame.hpp:131
std::string halo
Definition: frame.hpp:43
std::string halo_
Definition: frame.hpp:110
int get_location_y(const map_location &loc) const
Definition: display.cpp:736
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Definition: sound.cpp:989
frame_builder & submerge(const std::string &submerge)
Definition: frame.cpp:187
frame_parsed_parameters builder_
Definition: frame.hpp:246
bool does_not_change() const override
virtual const T get_current_element(int current_time, T default_val=T()) const override
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:755
frame_builder & auto_hflip(const bool auto_hflip)
Definition: frame.cpp:223
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 half_signed_value(int val)
Sign with Unicode "−" if negative.
boost::optional< color_t > text_color_
Definition: frame.hpp:117
frame_builder & sound(const std::string &sound)
Definition: frame.cpp:140
std::string get_original() const
std::string halo_mod
Definition: frame.hpp:48
progressive_image image_diagonal_
Definition: frame.hpp:167
std::string highlight_ratio_
Definition: frame.hpp:121
progressive_int x_
Definition: frame.hpp:186
boost::tribool primary_frame_
Definition: frame.hpp:193
std::string text_
Definition: frame.hpp:177
int duration() const
Definition: frame.hpp:156
frame_builder & auto_vflip(const bool auto_vflip)
Definition: frame.cpp:217
progressive_image image_
Definition: frame.hpp:166
progressive_double highlight_ratio_
Definition: frame.hpp:183
std::string y_
Definition: frame.hpp:125
progressive_int halo_y_
Definition: frame.hpp:173
progressive_pair< int > progressive_int
std::string directional_x_
Definition: frame.hpp:126
progressive_int drawing_layer_
Definition: frame.hpp:195
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:452
#define ftofxp(x)
IN: float or int - OUT: fixed_t.
Definition: math.hpp:312
progressive_int directional_x_
Definition: frame.hpp:188
Encapsulates the map of the game.
Definition: location.hpp:42
void float_label(const map_location &loc, const std::string &text, const color_t &color)
Function to float a label above a tile.
const std::string & get_filename() const
Definition: image.hpp:85
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
progressive_single< std::string > progressive_string
boost::optional< color_t > blend_with
Definition: frame.hpp:53
boost::optional< color_t > text_color_
Definition: frame.hpp:179
static lg::log_domain log_engine("engine")
double highlight_ratio
Definition: frame.hpp:56
boost::optional< color_t > blend_with_
Definition: frame.hpp:180
default layer for drawing units
Definition: display.hpp:822
std::string image_mod
Definition: frame.hpp:42
int duration_
Definition: frame.hpp:105
std::string bool_string(const bool value)
Converts a bool value to 'true' or 'false'.
frame_builder & offset(const std::string &offset)
Definition: frame.cpp:181
frame_builder & x(const std::string &x)
Definition: frame.cpp:193
std::string offset_
Definition: frame.hpp:122
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:44
bool does_not_change() const
Definition: frame.cpp:268
boost::tribool auto_vflip
Definition: frame.hpp:65
int w
frame_builder & primary_frame(const bool primary_frame)
Definition: frame.cpp:229
bool is_in_hex(const locator &i_locator)
function to check if an image fit into an hex return false if the image has not the standard size...
Definition: image.cpp:1062
frame_builder & directional_y(const std::string &directional_y)
Definition: frame.cpp:211
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:669
double blend_ratio
Definition: frame.hpp:55
progressive_double submerge_
Definition: frame.hpp:185
double submerge
Definition: frame.hpp:58
double offset
Definition: frame.hpp:57
Definition: display.hpp:43
#define ERR_NG
Definition: frame.cpp:23
ORIENTATION
Definition: halo.hpp:35
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:689
progressive_int directional_y_
Definition: frame.hpp:189
boost::tribool auto_vflip_
Definition: frame.hpp:129
this module manages the cache of images.
Definition: image.cpp:103
Standard logging facilities (interface).
std::string halo_mod_
Definition: frame.hpp:175
std::string image_diagonal_
Definition: frame.hpp:108
frame_builder & duration(const int duration)
Allow easy chained modifications.
Definition: frame.cpp:162
map_location get_direction(DIRECTION d, unsigned int n=1u) const
Definition: location.hpp:261
boost::tribool auto_hflip_
Definition: frame.hpp:130
progressive_double offset_
Definition: frame.hpp:184
frame_builder & highlight(const std::string &highlight)
Definition: frame.cpp:175
std::string halo_x_
Definition: frame.hpp:111
std::string x_
Definition: frame.hpp:124
boost::optional< color_t > blend_with_
Definition: frame.hpp:118
progressive_string halo_
Definition: frame.hpp:171
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
progressive_int y_
Definition: frame.hpp:187
std::string image_mod_
Definition: frame.hpp:109
iterator begin() const
Definition: display.cpp:660
std::shared_ptr< halo_record > handle
Definition: halo.hpp:31
boost::tribool primary_frame
Definition: frame.hpp:67
frame_builder & text(const std::string &text, const color_t text_color)
Definition: frame.cpp:146
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:477
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:153
progressive_pair< double > progressive_double
static game_display * get_singleton()
std::string submerge_
Definition: frame.hpp:123
std::string sound_
Definition: frame.hpp:114
boost::tribool auto_vflip_
Definition: frame.hpp:191