The Battle for Wesnoth  1.17.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_ = 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  const double disp_zoom = display::get_singleton()->get_zoom_factor();
526 
527  if(image != nullptr) {
528  bool facing_west = (
529  direction == map_location::NORTH_WEST ||
530  direction == map_location::SOUTH_WEST);
531 
532  bool facing_north = (
533  direction == map_location::NORTH_WEST ||
534  direction == map_location::NORTH ||
535  direction == map_location::NORTH_EAST);
536 
537  if(!current_data.auto_hflip) { facing_west = false; }
538  if(!current_data.auto_vflip) { facing_north = true; }
539 
540  int my_x = x + current_data.x * disp_zoom - image->w / 2;
541  int my_y = y + current_data.y * disp_zoom - image->h / 2;
542 
543  if(facing_west) {
544  my_x -= current_data.directional_x * disp_zoom;
545  } else {
546  my_x += current_data.directional_x * disp_zoom;
547  }
548 
549  if(facing_north) {
550  my_y += current_data.directional_y * disp_zoom;
551  } else {
552  my_y -= current_data.directional_y * disp_zoom;
553  }
554 
555  display::get_singleton()->render_image(my_x, my_y,
556  static_cast<display::drawing_layer>(display::LAYER_UNIT_FIRST + current_data.drawing_layer),
557  src, image, facing_west, false,
558  ftofxp(current_data.highlight_ratio), current_data.blend_with ? *current_data.blend_with : color_t(),
559  current_data.blend_ratio, current_data.submerge, !facing_north);
560  }
561 
562  halo_id.reset();
563 
564  if(!in_scope_of_frame) { //check after frame as first/last frame image used in defense/attack anims
565  return;
566  }
567 
568  // No halos, exit
569  if(current_data.halo.empty()) {
570  return;
571  }
572 
573  halo::ORIENTATION orientation;
574  switch(direction)
575  {
576  case map_location::NORTH:
578  orientation = halo::NORMAL;
579  break;
581  case map_location::SOUTH:
582  if(!current_data.auto_vflip) {
583  orientation = halo::NORMAL;
584  } else {
585  orientation = halo::VREVERSE;
586  }
587  break;
589  if(!current_data.auto_vflip) {
590  orientation = halo::HREVERSE;
591  } else {
592  orientation = halo::HVREVERSE;
593  }
594  break;
596  orientation = halo::HREVERSE;
597  break;
599  default:
600  orientation = halo::NORMAL;
601  break;
602  }
603 
604  if(direction != map_location::SOUTH_WEST && direction != map_location::NORTH_WEST) {
605  halo_id = halo_man.add(
606  static_cast<int>(x + current_data.halo_x * disp_zoom),
607  static_cast<int>(y + current_data.halo_y * disp_zoom),
608  current_data.halo + current_data.halo_mod,
609  map_location(-1, -1),
610  orientation
611  );
612  } else {
613  halo_id = halo_man.add(
614  static_cast<int>(x - current_data.halo_x * disp_zoom),
615  static_cast<int>(y + current_data.halo_y * disp_zoom),
616  current_data.halo + current_data.halo_mod,
617  map_location(-1, -1),
618  orientation
619  );
620  }
621 }
622 
623 std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time, const map_location& src, const map_location& dst,
624  const frame_parameters& animation_val, const frame_parameters& engine_val) const
625 {
627 
628  const int xsrc = disp->get_location_x(src);
629  const int ysrc = disp->get_location_y(src);
630  const int xdst = disp->get_location_x(dst);
631  const int ydst = disp->get_location_y(dst);
632  const map_location::DIRECTION direction = src.get_relative_dir(dst);
633 
634  const frame_parameters current_data = merge_parameters(frame_time, animation_val, engine_val);
635 
636  double tmp_offset = current_data.offset;
637  const int d2 = display::get_singleton()->hex_size() / 2;
638 
639  image::locator image_loc;
640  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
641  image_loc = image::locator(current_data.image_diagonal, current_data.image_mod);
642  }
643 
644  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
645  image_loc = image::locator(current_data.image, current_data.image_mod);
646  }
647 
648  // We always invalidate our own hex because we need to be called at redraw time even
649  // if we don't draw anything in the hex itself
650  std::set<map_location> result;
651  if(tmp_offset == 0 && current_data.x == 0 && current_data.directional_x == 0 && image::is_in_hex(image_loc)) {
652  result.insert(src);
653 
654  bool facing_north = (
655  direction == map_location::NORTH_WEST ||
656  direction == map_location::NORTH ||
657  direction == map_location::NORTH_EAST);
658 
659  if(!current_data.auto_vflip) { facing_north = true; }
660 
661  int my_y = current_data.y;
662  if(facing_north) {
663  my_y += current_data.directional_y;
664  } else {
665  my_y -= current_data.directional_y;
666  }
667 
668  if(my_y < 0) {
669  result.insert(src.get_direction(map_location::NORTH));
670  result.insert(src.get_direction(map_location::NORTH_EAST));
671  result.insert(src.get_direction(map_location::NORTH_WEST));
672  } else if(my_y > 0) {
673  result.insert(src.get_direction(map_location::SOUTH));
674  result.insert(src.get_direction(map_location::SOUTH_EAST));
675  result.insert(src.get_direction(map_location::SOUTH_WEST));
676  }
677  } else {
678  int w = 0, h = 0;
679 
680  {
681  surface image;
682  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
683  image = image::get_image(image_loc, image::SCALED_TO_ZOOM);
684  }
685 
686  if(image != nullptr) {
687  w = image->w;
688  h = image->h;
689  }
690  }
691 
692  if(w != 0 || h != 0) {
693  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc);
694  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc);
695 
696  bool facing_west = (
697  direction == map_location::NORTH_WEST ||
698  direction == map_location::SOUTH_WEST);
699 
700  bool facing_north = (
701  direction == map_location::NORTH_WEST ||
702  direction == map_location::NORTH ||
703  direction == map_location::NORTH_EAST);
704 
705  if(!current_data.auto_vflip) { facing_north = true; }
706  if(!current_data.auto_hflip) { facing_west = false; }
707 
708  int my_x = x + current_data.x + d2 - w / 2;
709  int my_y = y + current_data.y + d2 - h / 2;
710 
711  if(facing_west) {
712  my_x += current_data.directional_x;
713  } else {
714  my_x -= current_data.directional_x;
715  }
716 
717  if(facing_north) {
718  my_y += current_data.directional_y;
719  } else {
720  my_y -= current_data.directional_y;
721  }
722 
723  // Check if our underlying hexes are invalidated. If we need to update ourselves because we changed,
724  // invalidate our hexes and return whether or not was successful.
725  const SDL_Rect r {my_x, my_y, w, h};
726  display::rect_of_hexes underlying_hex = disp->hexes_under_rect(r);
727 
728  result.insert(src);
729  result.insert(underlying_hex.begin(), underlying_hex.end());
730  } else {
731  // We have no "redraw surface" but we still need to invalidate our own hex in case we have a halo
732  // and/or sound that needs a redraw.
733  result.insert(src);
734  result.insert(dst);
735  }
736  }
737 
738  return result;
739 }
740 
741 /**
742  * This function merges the value provided by:
743  * - the frame
744  * - the engine (poison, flying unit...)
745  * - the animation as a whole
746  *
747  * There is no absolute rule for merging, so creativity is the rule. If a value is never provided by the engine, assert.
748  * This way if it becomes used, people will easily find the right place to look.
749  */
750 const frame_parameters unit_frame::merge_parameters(int current_time, const frame_parameters& animation_val,
751  const frame_parameters& engine_val) const
752 {
753  frame_parameters result;
754  const frame_parameters& current_val = builder_.parameters(current_time);
755 
756  result.primary_frame = engine_val.primary_frame;
757  if(!boost::logic::indeterminate(animation_val.primary_frame)) {
758  result.primary_frame = animation_val.primary_frame;
759  }
760 
761  if(!boost::logic::indeterminate(current_val.primary_frame)) {
762  result.primary_frame = current_val.primary_frame;
763  }
764 
765  // Convert the tribool to bool
766  const bool primary = static_cast<bool>(result.primary_frame) || boost::logic::indeterminate(result.primary_frame);
767 
768  /** The engine provides a default image to use for the unit when none is available */
769  result.image = current_val.image.is_void() || current_val.image.get_filename().empty()
770  ? animation_val.image
771  : current_val.image;
772 
773  if(primary && (result.image.is_void() || result.image.get_filename().empty())) {
774  result.image = engine_val.image;
775  }
776 
777  /** The engine provides a default image to use for the unit when none is available */
778  result.image_diagonal = current_val.image_diagonal.is_void() || current_val.image_diagonal.get_filename().empty()
779  ? animation_val.image_diagonal
780  : current_val.image_diagonal;
781 
782  if(primary && (result.image_diagonal.is_void() || result.image_diagonal.get_filename().empty())) {
783  result.image_diagonal = engine_val.image_diagonal;
784  }
785 
786  /**
787  * The engine provides a string for "petrified" and "team color" modifications.
788  * Note that image_mod is the complete modification and halo_mod is only the TC part.
789  */
790  result.image_mod = current_val.image_mod + animation_val.image_mod;
791  if(primary) {
792  result.image_mod += engine_val.image_mod;
793  } else {
794  result.image_mod += engine_val.halo_mod;
795  }
796 
797  assert(engine_val.halo.empty());
798  result.halo = current_val.halo.empty() ? animation_val.halo : current_val.halo;
799 
800  assert(engine_val.halo_x == 0);
801  result.halo_x = current_val.halo_x ? current_val.halo_x : animation_val.halo_x;
802 
803  /** The engine provides a y modification for terrain with height adjust and flying units */
804  result.halo_y = current_val.halo_y ? current_val.halo_y : animation_val.halo_y;
805  result.halo_y += engine_val.halo_y;
806 
807  result.halo_mod = current_val.halo_mod + animation_val.halo_mod;
808  result.halo_mod += engine_val.halo_mod;
809 
810  assert(engine_val.duration == 0);
811  result.duration = current_val.duration;
812 
813  assert(engine_val.sound.empty());
814  result.sound = current_val.sound.empty() ? animation_val.sound : current_val.sound;
815 
816  assert(engine_val.text.empty());
817  result.text = current_val.text.empty() ? animation_val.text : current_val.text;
818 
819  assert(!engine_val.text_color);
820  result.text_color = current_val.text_color ? current_val.text_color : animation_val.text_color;
821 
822  /** The engine provides a blend color for poisoned units */
823  result.blend_with = current_val.blend_with ? current_val.blend_with : animation_val.blend_with;
824  if(primary && engine_val.blend_with) {
825  result.blend_with = engine_val.blend_with->blend_lighten(result.blend_with ? *result.blend_with : color_t(0,0,0));
826  }
827 
828  /** The engine provides a blend color for poisoned units */
829  result.blend_ratio = current_val.blend_ratio != 0 ? current_val.blend_ratio:animation_val.blend_ratio;
830  if(primary && engine_val.blend_ratio != 0) {
831  result.blend_ratio = std::min(result.blend_ratio + engine_val.blend_ratio, 1.0);
832  }
833 
834  /** The engine provides a highlight ratio for selected units and visible "invisible" units */
835  result.highlight_ratio = (current_val.highlight_ratio < 0.999 || current_val.highlight_ratio > 1.001) ?
836  current_val.highlight_ratio : animation_val.highlight_ratio;
837  if(primary && (engine_val.highlight_ratio < 0.999 || engine_val.highlight_ratio > 1.001)) {
838  result.highlight_ratio = result.highlight_ratio * engine_val.highlight_ratio; // selected unit
839  }
840 
841  assert(engine_val.offset == 0);
842  result.offset = (current_val.offset != -1000) ? current_val.offset : animation_val.offset;
843  if(result.offset == -1000) {
844  result.offset = 0.0;
845  }
846 
847  /** The engine provides a submerge for units in water */
848  result.submerge = current_val.submerge != 0 ? current_val.submerge : animation_val.submerge;
849  if(primary && engine_val.submerge != 0 && result.submerge == 0) {
850  result.submerge = engine_val.submerge;
851  }
852 
853  assert(engine_val.x == 0);
854  result.x = current_val.x ? current_val.x : animation_val.x;
855 
856  /** The engine provides a y modification for terrain with height adjust and flying units */
857  result.y = current_val.y?current_val.y:animation_val.y;
858  result.y += engine_val.y;
859 
860  assert(engine_val.directional_x == 0);
861  result.directional_x = current_val.directional_x ? current_val.directional_x : animation_val.directional_x;
862 
863  assert(engine_val.directional_y == 0);
864  result.directional_y = current_val.directional_y ? current_val.directional_y : animation_val.directional_y;
865 
868  ? current_val.drawing_layer
869  : animation_val.drawing_layer;
870 
871  /** The engine provides us with a default value to compare to. Update if different */
872  result.auto_hflip = engine_val.auto_hflip;
873 
874  if(!boost::logic::indeterminate(animation_val.auto_hflip)) {
875  result.auto_hflip = animation_val.auto_hflip;
876  }
877 
878  if(!boost::logic::indeterminate(current_val.auto_hflip)) {
879  result.auto_hflip = current_val.auto_hflip;
880  }
881 
882  if(boost::logic::indeterminate(result.auto_hflip)) {
883  result.auto_hflip = true;
884  }
885 
886  result.auto_vflip = engine_val.auto_vflip;
887 
888  if(!boost::logic::indeterminate(animation_val.auto_vflip)) {
889  result.auto_vflip = animation_val.auto_vflip;
890  }
891 
892  if(!boost::logic::indeterminate(current_val.auto_vflip)) {
893  result.auto_vflip = current_val.auto_vflip;
894  }
895 
896  if(boost::logic::indeterminate(result.auto_vflip)) {
897  result.auto_vflip = !primary;
898  }
899 
900  return result;
901 }
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:832
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:623
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:91
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:259
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:262
std::string text_
Definition: frame.hpp:116
bool has_attribute(config_key_type key) const
Definition: config.cpp:207
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:1551
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:766
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:305
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:678
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:687
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:834
std::string image_mod
Definition: frame.hpp:43
int get_location_y(const map_location &loc) const
Definition: display.cpp:754
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:749
#define ERR_NG
Definition: frame.cpp:23
ORIENTATION
Definition: halo.hpp:33
iterator end() const
Definition: display.cpp:682
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:750
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