The Battle for Wesnoth  1.15.0-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_ = 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  const auto& text_color_key = cfg[frame_string + "text_color"];
94  if(!text_color_key.empty()) {
95  try {
96  text_color_ = color_t::from_rgb_string(text_color_key);
97  } catch(const std::invalid_argument& e) {
98  // Might be thrown either due to an incorrect number of elements or std::stoul failure.
99  ERR_NG << "Invalid RBG text color in unit animation: " << text_color_key.str()
100  << "\n" << e.what() << "\n;";
101  }
102  }
103 
104  if(const config::attribute_value* v = cfg.get(frame_string + "duration")) {
105  duration(*v);
106  } else if(!cfg.get(frame_string + "end")) {
107  int halo_duration = (progressive_string(halo_, 1)).duration();
108  int image_duration = (progressive_image(image_, 1)).duration();
109  int image_diagonal_duration = (progressive_image(image_diagonal_, 1)).duration();
110 
111  duration(std::max(std::max(image_duration, image_diagonal_duration), halo_duration));
112  } else {
113  duration(cfg[frame_string + "end"].to_int() - cfg[frame_string + "begin"].to_int());
114  }
115 
116  duration_ = std::max(duration_, 1);
117 
118  const auto& blend_color_key = cfg[frame_string + "blend_color"];
119  if(!blend_color_key.empty()) {
120  try {
121  blend_with_ = color_t::from_rgb_string(blend_color_key);
122  } catch(const std::invalid_argument& e) {
123  // Might be thrown either due to an incorrect number of elements or std::stoul failure.
124  ERR_NG << "Invalid RBG blend color in unit animation: " << blend_color_key.str()
125  << "\n" << e.what() << "\n;";
126  }
127  }
128 }
129 
130 frame_builder& frame_builder::image(const std::string& image ,const std::string& image_mod)
131 {
132  image_ = image;
133  image_mod_ = image_mod;
134  return *this;
135 }
136 
137 frame_builder& frame_builder::image_diagonal(const std::string& image_diagonal,const std::string& image_mod)
138 {
140  image_mod_ = image_mod;
141  return *this;
142 }
143 
145 {
146  sound_ = sound;
147  return *this;
148 }
149 
150 frame_builder& frame_builder::text(const std::string& text,const color_t text_color)
151 {
152  text_ = text;
153  text_color_ = text_color;
154  return *this;
155 }
156 
157 frame_builder& frame_builder::halo(const std::string& halo, const std::string& halo_x, const std::string& halo_y,const std::string& halo_mod)
158 {
159  halo_ = halo;
160  halo_x_ = halo_x;
161  halo_y_ = halo_y;
162  halo_mod_= halo_mod;
163  return *this;
164 }
165 
167 {
169  return *this;
170 }
171 
172 frame_builder& frame_builder::blend(const std::string& blend_ratio,const color_t blend_color)
173 {
174  blend_with_ = blend_color;
175  blend_ratio_ = blend_ratio;
176  return *this;
177 }
178 
180 {
182  return *this;
183 }
184 
186 {
187  offset_ = offset;
188  return *this;
189 }
190 
192 {
194  return *this;
195 }
196 
197 frame_builder& frame_builder::x(const std::string& x)
198 {
199  x_ = x;
200  return *this;
201 }
202 
203 frame_builder& frame_builder::y(const std::string& y)
204 {
205  y_ = y;
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 {
242  return *this;
243 }
244 
246  : duration_(duration ? duration : builder.duration_)
247  , image_(builder.image_,duration_)
249  , image_mod_(builder.image_mod_)
250  , halo_(builder.halo_,duration_)
251  , halo_x_(builder.halo_x_,duration_)
252  , halo_y_(builder.halo_y_,duration_)
253  , halo_mod_(builder.halo_mod_)
254  , sound_(builder.sound_)
255  , text_(builder.text_)
256  , text_color_(builder.text_color_)
257  , blend_with_(builder.blend_with_)
260  , offset_(builder.offset_,duration_)
261  , submerge_(builder.submerge_,duration_)
262  , x_(builder.x_,duration_)
263  , y_(builder.y_,duration_)
266  , auto_vflip_(builder.auto_vflip_)
267  , auto_hflip_(builder.auto_hflip_)
268  , primary_frame_(builder.primary_frame_)
270 {}
271 
273 {
274  return
284  x_.does_not_change() &&
285  y_.does_not_change() &&
289 }
290 
292 {
293  return !this->does_not_change();
294 }
295 
297 {
298  frame_parameters result;
299  result.duration = duration_;
300  result.image = image_.get_current_element(current_time);
301  result.image_diagonal = image_diagonal_.get_current_element(current_time);
302  result.image_mod = image_mod_;
303  result.halo = halo_.get_current_element(current_time);
304  result.halo_x = halo_x_.get_current_element(current_time);
305  result.halo_y = halo_y_.get_current_element(current_time);
306  result.halo_mod = halo_mod_;
307  result.sound = sound_;
308  result.text = text_;
309  result.text_color = text_color_;
310  result.blend_with = blend_with_;
311  result.blend_ratio = blend_ratio_.get_current_element(current_time);
312  result.highlight_ratio = highlight_ratio_.get_current_element(current_time,1.0);
313  result.offset = offset_.get_current_element(current_time,-1000);
314  result.submerge = submerge_.get_current_element(current_time);
315  result.x = x_.get_current_element(current_time);
316  result.y = y_.get_current_element(current_time);
317  result.directional_x = directional_x_.get_current_element(current_time);
318  result.directional_y = directional_y_.get_current_element(current_time);
319  result.auto_vflip = auto_vflip_;
320  result.auto_hflip = auto_hflip_;
321  result.primary_frame = primary_frame_;
323  return result;
324 }
325 
327  const std::string& highlight,
328  const std::string& blend_ratio,
329  color_t blend_color,
330  const std::string& offset,
331  const std::string& layer,
332  const std::string& modifiers)
333 {
334  if(!highlight.empty()) {
335  highlight_ratio_ = progressive_double(highlight,duration);
336  } else if(duration != duration_){
338  }
339 
340  if(!offset.empty()) {
341  offset_ = progressive_double(offset,duration);
342  } else if(duration != duration_){
344  }
345 
346  if(!blend_ratio.empty()) {
347  blend_ratio_ = progressive_double(blend_ratio,duration);
348  blend_with_ = blend_color;
349  } else if(duration != duration_){
351  }
352 
353  if(!layer.empty()) {
354  drawing_layer_ = progressive_int(layer,duration);
355  } else if(duration != duration_){
357  }
358 
359  if(!modifiers.empty()) {
360  image_mod_ += modifiers;
361  }
362 
363  if(duration != duration_) {
375  }
376 }
377 
378 std::vector<std::string> frame_parsed_parameters::debug_strings() const
379 {
380  std::vector<std::string> v;
381 
382  if(duration_ > 0) {
383  v.emplace_back("duration=" + utils::half_signed_value(duration_));
384  }
385 
386  if(!image_.get_original().empty()) {
387  v.emplace_back("image=" + image_.get_original());
388  }
389 
390  if(!image_diagonal_.get_original().empty()) {
391  v.emplace_back("image_diagonal=" + image_diagonal_.get_original());
392  }
393 
394  if(!image_mod_.empty()) {
395  v.emplace_back("image_mod=" + image_mod_);
396  }
397 
398  if(!halo_.get_original().empty()) {
399  v.emplace_back("halo=" + halo_.get_original());
400  }
401 
402  if(!halo_x_.get_original().empty()) {
403  v.emplace_back("halo_x=" + halo_x_.get_original());
404  }
405 
406  if(!halo_y_.get_original().empty()) {
407  v.emplace_back("halo_y=" + halo_y_.get_original());
408  }
409 
410  if(!halo_mod_.empty()) {
411  v.emplace_back("halo_mod=" + halo_mod_);
412  }
413 
414  if(!sound_.empty()) {
415  v.emplace_back("sound=" + sound_);
416  }
417 
418  if(!text_.empty()) {
419  v.emplace_back("text=" + text_);
420 
421  if(text_color_) {
422  v.emplace_back("text_color=" + text_color_->to_rgba_string());
423  }
424  }
425 
426  if(!blend_ratio_.get_original().empty()) {
427  v.emplace_back("blend_ratio=" + blend_ratio_.get_original());
428 
429  if(blend_with_) {
430  v.emplace_back("blend_with=" + blend_with_->to_rgba_string());
431  }
432  }
433 
434  if(!highlight_ratio_.get_original().empty()) {
435  v.emplace_back("highlight_ratio=" + highlight_ratio_.get_original());
436  }
437 
438  if(!offset_.get_original().empty()) {
439  v.emplace_back("offset=" + offset_.get_original());
440  }
441 
442  if(!submerge_.get_original().empty()) {
443  v.emplace_back("submerge=" + submerge_.get_original());
444  }
445 
446  if(!x_.get_original().empty()) {
447  v.emplace_back("x=" + x_.get_original());
448  }
449 
450  if(!y_.get_original().empty()) {
451  v.emplace_back("y=" + y_.get_original());
452  }
453 
454  if(!directional_x_.get_original().empty()) {
455  v.emplace_back("directional_x=" + directional_x_.get_original());
456  }
457 
458  if(!directional_y_.get_original().empty()) {
459  v.emplace_back("directional_y=" + directional_y_.get_original());
460  }
461 
462  if(!boost::indeterminate(auto_vflip_)) {
463  v.emplace_back("auto_vflip=" + utils::bool_string(auto_vflip_));
464  }
465 
466  if(!boost::indeterminate(auto_hflip_)) {
467  v.emplace_back("auto_hflip=" + utils::bool_string(auto_hflip_));
468  }
469 
470  if(!boost::indeterminate(primary_frame_)) {
471  v.emplace_back("primary_frame=" + utils::bool_string(primary_frame_));
472  }
473 
474  if(!drawing_layer_.get_original().empty()) {
475  v.emplace_back("drawing_layer=" + drawing_layer_.get_original());
476  }
477 
478  return v;
479 }
480 
481 void unit_frame::redraw(const int frame_time, bool on_start_time, bool in_scope_of_frame,
482  const map_location& src, const map_location& dst,
483  halo::handle& halo_id, halo::manager& halo_man,
484  const frame_parameters& animation_val, const frame_parameters& engine_val) const
485 {
487 
488  const int xsrc = game_disp->get_location_x(src);
489  const int ysrc = game_disp->get_location_y(src);
490  const int xdst = game_disp->get_location_x(dst);
491  const int ydst = game_disp->get_location_y(dst);
492  const map_location::DIRECTION direction = src.get_relative_dir(dst);
493 
494  const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
495  double tmp_offset = current_data.offset;
496 
497  // Debug code to see the number of frames and their position
498  //if(tmp_offset) {
499  // std::cout << static_cast<int>(tmp_offset * 100) << "," << "\n";
500  //}
501 
502  if(on_start_time) {
503  // Stuff that should be done only once per frame
504  if(!current_data.sound.empty() ) {
505  sound::play_sound(current_data.sound);
506  }
507 
508  if(!current_data.text.empty() && current_data.text_color) {
509  game_disp->float_label(src, current_data.text, *current_data.text_color);
510  }
511  }
512 
513  image::locator image_loc;
514  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
515  image_loc = image::locator(current_data.image_diagonal, current_data.image_mod);
516  }
517 
518  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
519  image_loc = image::locator(current_data.image, current_data.image_mod);
520  }
521 
522  surface image;
523  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
524  image=image::get_image(image_loc, image::SCALED_TO_ZOOM);
525  }
526 
527  const int d2 = display::get_singleton()->hex_size() / 2;
528 
529  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc) + d2;
530  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc) + d2;
531 
532  if(image != nullptr) {
533  bool facing_west = (
534  direction == map_location::NORTH_WEST ||
535  direction == map_location::SOUTH_WEST);
536 
537  bool facing_north = (
538  direction == map_location::NORTH_WEST ||
539  direction == map_location::NORTH ||
540  direction == map_location::NORTH_EAST);
541 
542  if(!current_data.auto_hflip) { facing_west = false; }
543  if(!current_data.auto_vflip) { facing_north = true; }
544 
545  int my_x = x + current_data.x - image->w / 2;
546  int my_y = y + current_data.y - image->h / 2;
547 
548  if(facing_west) {
549  my_x -= current_data.directional_x;
550  } else {
551  my_x += current_data.directional_x;
552  }
553 
554  if(facing_north) {
555  my_y += current_data.directional_y;
556  } else {
557  my_y -= current_data.directional_y;
558  }
559 
560  display::get_singleton()->render_image(my_x, my_y,
561  static_cast<display::drawing_layer>(display::LAYER_UNIT_FIRST + current_data.drawing_layer),
562  src, image, facing_west, false,
563  ftofxp(current_data.highlight_ratio), current_data.blend_with ? *current_data.blend_with : color_t(),
564  current_data.blend_ratio, current_data.submerge, !facing_north);
565  }
566 
567  halo_id.reset();
568 
569  if(!in_scope_of_frame) { //check after frame as first/last frame image used in defense/attack anims
570  return;
571  }
572 
573  // No halos, exit
574  if(current_data.halo.empty()) {
575  return;
576  }
577 
578  halo::ORIENTATION orientation;
579  switch(direction)
580  {
581  case map_location::NORTH:
583  orientation = halo::NORMAL;
584  break;
586  case map_location::SOUTH:
587  if(!current_data.auto_vflip) {
588  orientation = halo::NORMAL;
589  } else {
590  orientation = halo::VREVERSE;
591  }
592  break;
594  if(!current_data.auto_vflip) {
595  orientation = halo::HREVERSE;
596  } else {
597  orientation = halo::HVREVERSE;
598  }
599  break;
601  orientation = halo::HREVERSE;
602  break;
604  default:
605  orientation = halo::NORMAL;
606  break;
607  }
608 
609  if(direction != map_location::SOUTH_WEST && direction != map_location::NORTH_WEST) {
610  halo_id = halo_man.add(
611  static_cast<int>(x + current_data.halo_x * display::get_singleton()->get_zoom_factor()),
612  static_cast<int>(y + current_data.halo_y * display::get_singleton()->get_zoom_factor()),
613  current_data.halo + current_data.halo_mod,
614  map_location(-1, -1),
615  orientation
616  );
617  } else {
618  halo_id = halo_man.add(
619  static_cast<int>(x - current_data.halo_x * display::get_singleton()->get_zoom_factor()),
620  static_cast<int>(y + current_data.halo_y * display::get_singleton()->get_zoom_factor()),
621  current_data.halo + current_data.halo_mod,
622  map_location(-1, -1),
623  orientation
624  );
625  }
626 }
627 
628 std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time, const map_location& src, const map_location& dst,
629  const frame_parameters& animation_val, const frame_parameters& engine_val) const
630 {
632 
633  const int xsrc = disp->get_location_x(src);
634  const int ysrc = disp->get_location_y(src);
635  const int xdst = disp->get_location_x(dst);
636  const int ydst = disp->get_location_y(dst);
637  const map_location::DIRECTION direction = src.get_relative_dir(dst);
638 
639  const frame_parameters current_data = merge_parameters(frame_time, animation_val, engine_val);
640 
641  double tmp_offset = current_data.offset;
642  const int d2 = display::get_singleton()->hex_size() / 2;
643 
644  image::locator image_loc;
645  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
646  image_loc = image::locator(current_data.image_diagonal, current_data.image_mod);
647  }
648 
649  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
650  image_loc = image::locator(current_data.image, current_data.image_mod);
651  }
652 
653  // We always invalidate our own hex because we need to be called at redraw time even
654  // if we don't draw anything in the hex itself
655  std::set<map_location> result;
656  if(tmp_offset == 0 && current_data.x == 0 && current_data.directional_x == 0 && image::is_in_hex(image_loc)) {
657  result.insert(src);
658 
659  bool facing_north = (
660  direction == map_location::NORTH_WEST ||
661  direction == map_location::NORTH ||
662  direction == map_location::NORTH_EAST);
663 
664  if(!current_data.auto_vflip) { facing_north = true; }
665 
666  int my_y = current_data.y;
667  if(facing_north) {
668  my_y += current_data.directional_y;
669  } else {
670  my_y -= current_data.directional_y;
671  }
672 
673  if(my_y < 0) {
674  result.insert(src.get_direction(map_location::NORTH));
675  result.insert(src.get_direction(map_location::NORTH_EAST));
676  result.insert(src.get_direction(map_location::NORTH_WEST));
677  } else if(my_y > 0) {
678  result.insert(src.get_direction(map_location::SOUTH));
679  result.insert(src.get_direction(map_location::SOUTH_EAST));
680  result.insert(src.get_direction(map_location::SOUTH_WEST));
681  }
682  } else {
683  int w = 0, h = 0;
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 }
const frame_parameters parameters(int current_time) const
Getters for the different parameters.
Definition: frame.cpp:296
virtual bool does_not_change() const
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: picture.cpp:1022
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:824
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:628
std::string image_
Definition: frame.hpp:108
frame_builder & y(const std::string &y)
Definition: frame.cpp:203
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:88
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:245
frame_builder & blend(const std::string &blend_ratio, const color_t blend_color)
Definition: frame.cpp:172
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:225
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:255
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:258
std::string text_
Definition: frame.hpp:116
bool has_attribute(config_key_type key) const
Definition: config.cpp:217
boost::optional< color_t > text_color
Definition: frame.hpp:53
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:1521
int directional_x
Definition: frame.hpp:63
frame_builder & drawing_layer(const std::string &drawing_layer)
Definition: frame.cpp:239
frame_builder & image_diagonal(const std::string &image_diagonal, const std::string &image_mod="")
Definition: frame.cpp:137
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:744
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:301
frame_builder & directional_x(const std::string &directional_x)
Definition: frame.cpp:209
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:326
frame_builder & image(const std::string &image, const std::string &image_mod="")
Definition: frame.cpp:130
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:650
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Definition: sound.cpp:980
map_location get_direction(DIRECTION dir, unsigned int n=1u) const
Definition: location.cpp:402
frame_builder & submerge(const std::string &submerge)
Definition: frame.cpp:191
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:227
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
boost::optional< color_t > text_color_
Definition: frame.hpp:118
frame_builder & sound(const std::string &sound)
Definition: frame.cpp:144
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:221
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
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:659
std::string directional_x_
Definition: frame.hpp:127
progressive_int drawing_layer_
Definition: frame.hpp:196
std::vector< std::string > debug_strings() const
Contents of frame in strings.
Definition: frame.cpp:378
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:297
progressive_int directional_x_
Definition: frame.hpp:189
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.
progressive_single< std::string > progressive_string
boost::optional< color_t > blend_with
Definition: frame.hpp:54
boost::optional< color_t > text_color_
Definition: frame.hpp:180
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:481
static lg::log_domain log_engine("engine")
double highlight_ratio
Definition: frame.hpp:57
boost::optional< color_t > blend_with_
Definition: frame.hpp:181
int duration() const
Definition: frame.hpp:157
default layer for drawing units
Definition: display.hpp:826
std::string image_mod
Definition: frame.hpp:43
int get_location_y(const map_location &loc) const
Definition: display.cpp:726
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:185
bool need_update() const
Definition: frame.cpp:291
frame_builder & x(const std::string &x)
Definition: frame.cpp:197
std::string offset_
Definition: frame.hpp:123
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:44
boost::tribool auto_vflip
Definition: frame.hpp:66
int w
const std::string & get_filename() const
Definition: picture.hpp:85
frame_builder & primary_frame(const bool primary_frame)
Definition: frame.cpp:233
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: picture.cpp:1153
frame_builder & directional_y(const std::string &directional_y)
Definition: frame.cpp:215
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:721
#define ERR_NG
Definition: frame.cpp:23
ORIENTATION
Definition: halo.hpp:35
iterator end() const
Definition: display.cpp:654
progressive_int directional_y_
Definition: frame.hpp:190
boost::tribool auto_vflip_
Definition: frame.hpp:130
this module manages the cache of images.
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:166
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:179
std::string halo_x_
Definition: frame.hpp:112
std::string x_
Definition: frame.hpp:125
boost::optional< color_t > blend_with_
Definition: frame.hpp:119
bool is_void() const
Definition: picture.hpp:96
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:92
progressive_int y_
Definition: frame.hpp:188
std::string image_mod_
Definition: frame.hpp:110
std::shared_ptr< halo_record > handle
Definition: halo.hpp:31
boost::tribool primary_frame
Definition: frame.hpp:68
frame_builder & text(const std::string &text, const color_t text_color)
Definition: frame.cpp:150
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:272
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:157
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
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