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 "map/hex_rect.hpp"
21 #include "sdl/render_utils.hpp"
22 #include "sound.hpp"
23 
24 static lg::log_domain log_engine("engine");
25 #define ERR_NG LOG_STREAM(err, log_engine)
26 
28  : duration(0)
29  , halo_x(0)
30  , halo_y(0)
31  , blend_ratio(0.0)
32  , highlight_ratio(1.0)
33  , offset(0)
34  , submerge(0.0)
35  , x(0)
36  , y(0)
37  , directional_x(0)
38  , directional_y(0)
39  , auto_vflip(boost::logic::indeterminate)
40  , auto_hflip(boost::logic::indeterminate)
41  , primary_frame(boost::logic::indeterminate)
42  , layer(drawing_queue::LAYER_UNIT_DEFAULT - drawing_queue::LAYER_UNIT_FIRST)
43 {}
44 
46  : duration_(1)
47  , auto_vflip_(boost::logic::indeterminate)
48  , auto_hflip_(boost::logic::indeterminate)
49  , primary_frame_(boost::logic::indeterminate)
50  , layer_(std::to_string(drawing_queue::LAYER_UNIT_DEFAULT - drawing_queue::LAYER_UNIT_FIRST))
51 {}
52 
53 frame_builder::frame_builder(const config& cfg,const std::string& frame_string)
54  : duration_(1)
55  , image_(cfg[frame_string + "image"])
56  , image_diagonal_(cfg[frame_string + "image_diagonal"])
57  , image_mod_(cfg[frame_string + "image_mod"])
58  , halo_(cfg[frame_string + "halo"])
59  , halo_x_(cfg[frame_string + "halo_x"])
60  , halo_y_(cfg[frame_string + "halo_y"])
61  , halo_mod_(cfg[frame_string + "halo_mod"])
62  , sound_(cfg[frame_string + "sound"])
63  , text_(cfg[frame_string + "text"])
64  , blend_ratio_(cfg[frame_string + "blend_ratio"])
65  , highlight_ratio_(cfg[frame_string + "alpha"])
66  , offset_(cfg[frame_string + "offset"])
67  , submerge_(cfg[frame_string + "submerge"])
68  , x_(cfg[frame_string + "x"])
69  , y_(cfg[frame_string + "y"])
70  , directional_x_(cfg[frame_string + "directional_x"])
71  , directional_y_(cfg[frame_string + "directional_y"])
72  , auto_vflip_(boost::logic::indeterminate)
73  , auto_hflip_(boost::logic::indeterminate)
74  , primary_frame_(boost::logic::indeterminate)
75  , layer_(cfg[frame_string + "layer"])
76 {
77  if(!cfg.has_attribute(frame_string + "auto_vflip")) {
78  auto_vflip_ = boost::logic::indeterminate;
79  } else {
80  auto_vflip_ = cfg[frame_string + "auto_vflip"].to_bool();
81  }
82 
83  if(!cfg.has_attribute(frame_string + "auto_hflip")) {
84  auto_hflip_ = boost::logic::indeterminate;
85  } else {
86  auto_hflip_ = cfg[frame_string + "auto_hflip"].to_bool();
87  }
88 
89  if(!cfg.has_attribute(frame_string + "primary")) {
90  primary_frame_ = boost::logic::indeterminate;
91  } else {
92  primary_frame_ = cfg[frame_string + "primary"].to_bool();
93  }
94 
95  const auto& text_color_key = cfg[frame_string + "text_color"];
96  if(!text_color_key.empty()) {
97  try {
98  text_color_ = color_t::from_rgb_string(text_color_key);
99  } catch(const std::invalid_argument& e) {
100  // Might be thrown either due to an incorrect number of elements or std::stoul failure.
101  ERR_NG << "Invalid RBG text color in unit animation: " << text_color_key.str()
102  << "\n" << e.what() << "\n;";
103  }
104  }
105 
106  if(const config::attribute_value* v = cfg.get(frame_string + "duration")) {
107  duration(*v);
108  } else if(!cfg.get(frame_string + "end")) {
109  int halo_duration = (progressive_string(halo_, 1)).duration();
110  int image_duration = (progressive_image(image_, 1)).duration();
111  int image_diagonal_duration = (progressive_image(image_diagonal_, 1)).duration();
112 
113  duration(std::max(std::max(image_duration, image_diagonal_duration), halo_duration));
114  } else {
115  duration(cfg[frame_string + "end"].to_int() - cfg[frame_string + "begin"].to_int());
116  }
117 
118  duration_ = std::max(duration_, 1);
119 
120  const auto& blend_color_key = cfg[frame_string + "blend_color"];
121  if(!blend_color_key.empty()) {
122  try {
123  blend_with_ = color_t::from_rgb_string(blend_color_key);
124  } catch(const std::invalid_argument& e) {
125  // Might be thrown either due to an incorrect number of elements or std::stoul failure.
126  ERR_NG << "Invalid RBG blend color in unit animation: " << blend_color_key.str()
127  << "\n" << e.what() << "\n;";
128  }
129  }
130 }
131 
132 frame_builder& frame_builder::image(const std::string& image ,const std::string& image_mod)
133 {
134  image_ = image;
135  image_mod_ = image_mod;
136  return *this;
137 }
138 
139 frame_builder& frame_builder::image_diagonal(const std::string& image_diagonal,const std::string& image_mod)
140 {
142  image_mod_ = image_mod;
143  return *this;
144 }
145 
147 {
148  sound_ = sound;
149  return *this;
150 }
151 
152 frame_builder& frame_builder::text(const std::string& text,const color_t text_color)
153 {
154  text_ = text;
155  text_color_ = text_color;
156  return *this;
157 }
158 
159 frame_builder& frame_builder::halo(const std::string& halo, const std::string& halo_x, const std::string& halo_y,const std::string& halo_mod)
160 {
161  halo_ = halo;
162  halo_x_ = halo_x;
163  halo_y_ = halo_y;
164  halo_mod_= halo_mod;
165  return *this;
166 }
167 
169 {
171  return *this;
172 }
173 
174 frame_builder& frame_builder::blend(const std::string& blend_ratio,const color_t blend_color)
175 {
176  blend_with_ = blend_color;
177  blend_ratio_ = blend_ratio;
178  return *this;
179 }
180 
182 {
184  return *this;
185 }
186 
188 {
189  offset_ = offset;
190  return *this;
191 }
192 
194 {
196  return *this;
197 }
198 
199 frame_builder& frame_builder::x(const std::string& x)
200 {
201  x_ = x;
202  return *this;
203 }
204 
205 frame_builder& frame_builder::y(const std::string& y)
206 {
207  y_ = y;
208  return *this;
209 }
210 
212 {
214  return *this;
215 }
216 
218 {
220  return *this;
221 }
222 
224 {
226  return *this;
227 }
228 
230 {
232  return *this;
233 }
234 
236 {
238  return *this;
239 }
240 
242 {
243  layer_=layer;
244  return *this;
245 }
246 
248  : duration_(duration ? duration : builder.duration_)
249  , image_(builder.image_,duration_)
251  , image_mod_(builder.image_mod_)
252  , halo_(builder.halo_,duration_)
253  , halo_x_(builder.halo_x_,duration_)
254  , halo_y_(builder.halo_y_,duration_)
255  , halo_mod_(builder.halo_mod_)
256  , sound_(builder.sound_)
257  , text_(builder.text_)
258  , text_color_(builder.text_color_)
259  , blend_with_(builder.blend_with_)
262  , offset_(builder.offset_,duration_)
263  , submerge_(builder.submerge_,duration_)
264  , x_(builder.x_,duration_)
265  , y_(builder.y_,duration_)
268  , auto_vflip_(builder.auto_vflip_)
269  , auto_hflip_(builder.auto_hflip_)
270  , primary_frame_(builder.primary_frame_)
271  , layer_(builder.layer_,duration_)
272 {}
273 
275 {
276  return
286  x_.does_not_change() &&
287  y_.does_not_change() &&
291 }
292 
294 {
295  return !this->does_not_change();
296 }
297 
299 {
300  frame_parameters result;
301  result.duration = duration_;
302  result.image = image_.get_current_element(current_time);
303  result.image_diagonal = image_diagonal_.get_current_element(current_time);
304  result.image_mod = image_mod_;
305  result.halo = halo_.get_current_element(current_time);
306  result.halo_x = halo_x_.get_current_element(current_time);
307  result.halo_y = halo_y_.get_current_element(current_time);
308  result.halo_mod = halo_mod_;
309  result.sound = sound_;
310  result.text = text_;
311  result.text_color = text_color_;
312  result.blend_with = blend_with_;
313  result.blend_ratio = blend_ratio_.get_current_element(current_time);
314  result.highlight_ratio = highlight_ratio_.get_current_element(current_time,1.0);
315  result.offset = offset_.get_current_element(current_time,-1000);
316  result.submerge = submerge_.get_current_element(current_time);
317  result.x = x_.get_current_element(current_time);
318  result.y = y_.get_current_element(current_time);
319  result.directional_x = directional_x_.get_current_element(current_time);
320  result.directional_y = directional_y_.get_current_element(current_time);
321  result.auto_vflip = auto_vflip_;
322  result.auto_hflip = auto_hflip_;
323  result.primary_frame = primary_frame_;
325  return result;
326 }
327 
329  const std::string& highlight,
330  const std::string& blend_ratio,
331  color_t blend_color,
332  const std::string& offset,
333  const std::string& layer,
334  const std::string& modifiers)
335 {
336  if(!highlight.empty()) {
337  highlight_ratio_ = progressive_double(highlight,duration);
338  } else if(duration != duration_){
340  }
341 
342  if(!offset.empty()) {
343  offset_ = progressive_double(offset,duration);
344  } else if(duration != duration_){
346  }
347 
348  if(!blend_ratio.empty()) {
349  blend_ratio_ = progressive_double(blend_ratio,duration);
350  blend_with_ = blend_color;
351  } else if(duration != duration_){
353  }
354 
355  if(!layer.empty()) {
356  layer_ = progressive_int(layer,duration);
357  } else if(duration != duration_){
359  }
360 
361  if(!modifiers.empty()) {
362  image_mod_ += modifiers;
363  }
364 
365  if(duration != duration_) {
377  }
378 }
379 
380 std::vector<std::string> frame_parsed_parameters::debug_strings() const
381 {
382  std::vector<std::string> v;
383 
384  if(duration_ > 0) {
385  v.emplace_back("duration=" + utils::half_signed_value(duration_));
386  }
387 
388  if(!image_.get_original().empty()) {
389  v.emplace_back("image=" + image_.get_original());
390  }
391 
392  if(!image_diagonal_.get_original().empty()) {
393  v.emplace_back("image_diagonal=" + image_diagonal_.get_original());
394  }
395 
396  if(!image_mod_.empty()) {
397  v.emplace_back("image_mod=" + image_mod_);
398  }
399 
400  if(!halo_.get_original().empty()) {
401  v.emplace_back("halo=" + halo_.get_original());
402  }
403 
404  if(!halo_x_.get_original().empty()) {
405  v.emplace_back("halo_x=" + halo_x_.get_original());
406  }
407 
408  if(!halo_y_.get_original().empty()) {
409  v.emplace_back("halo_y=" + halo_y_.get_original());
410  }
411 
412  if(!halo_mod_.empty()) {
413  v.emplace_back("halo_mod=" + halo_mod_);
414  }
415 
416  if(!sound_.empty()) {
417  v.emplace_back("sound=" + sound_);
418  }
419 
420  if(!text_.empty()) {
421  v.emplace_back("text=" + text_);
422 
423  if(text_color_) {
424  v.emplace_back("text_color=" + text_color_->to_rgba_string());
425  }
426  }
427 
428  if(!blend_ratio_.get_original().empty()) {
429  v.emplace_back("blend_ratio=" + blend_ratio_.get_original());
430 
431  if(blend_with_) {
432  v.emplace_back("blend_with=" + blend_with_->to_rgba_string());
433  }
434  }
435 
436  if(!highlight_ratio_.get_original().empty()) {
437  v.emplace_back("highlight_ratio=" + highlight_ratio_.get_original());
438  }
439 
440  if(!offset_.get_original().empty()) {
441  v.emplace_back("offset=" + offset_.get_original());
442  }
443 
444  if(!submerge_.get_original().empty()) {
445  v.emplace_back("submerge=" + submerge_.get_original());
446  }
447 
448  if(!x_.get_original().empty()) {
449  v.emplace_back("x=" + x_.get_original());
450  }
451 
452  if(!y_.get_original().empty()) {
453  v.emplace_back("y=" + y_.get_original());
454  }
455 
456  if(!directional_x_.get_original().empty()) {
457  v.emplace_back("directional_x=" + directional_x_.get_original());
458  }
459 
460  if(!directional_y_.get_original().empty()) {
461  v.emplace_back("directional_y=" + directional_y_.get_original());
462  }
463 
464  if(!boost::indeterminate(auto_vflip_)) {
465  v.emplace_back("auto_vflip=" + utils::bool_string(auto_vflip_));
466  }
467 
468  if(!boost::indeterminate(auto_hflip_)) {
469  v.emplace_back("auto_hflip=" + utils::bool_string(auto_hflip_));
470  }
471 
472  if(!boost::indeterminate(primary_frame_)) {
473  v.emplace_back("primary_frame=" + utils::bool_string(primary_frame_));
474  }
475 
476  if(!layer_.get_original().empty()) {
477  v.emplace_back("layer=" + layer_.get_original());
478  }
479 
480  return v;
481 }
482 
483 void unit_frame::redraw(const int frame_time, bool on_start_time, bool in_scope_of_frame,
484  const map_location& src, const map_location& dst,
485  halo::handle& halo_id, halo::manager& halo_man,
486  const frame_parameters& animation_val, const frame_parameters& engine_val) const
487 {
489 
490  const int xsrc = game_disp->get_location_x(src);
491  const int ysrc = game_disp->get_location_y(src);
492  const int xdst = game_disp->get_location_x(dst);
493  const int ydst = game_disp->get_location_y(dst);
494  const map_location::DIRECTION direction = src.get_relative_dir(dst);
495 
496  const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
497  double tmp_offset = current_data.offset;
498 
499  // Debug code to see the number of frames and their position
500  //if(tmp_offset) {
501  // std::cout << static_cast<int>(tmp_offset * 100) << "," << "\n";
502  //}
503 
504  if(on_start_time) {
505  // Stuff that should be done only once per frame
506  if(!current_data.sound.empty() ) {
507  sound::play_sound(current_data.sound);
508  }
509 
510  if(!current_data.text.empty() && current_data.text_color) {
511  game_disp->float_label(src, current_data.text, *current_data.text_color);
512  }
513  }
514 
515  image::locator image_loc;
516  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
517  image_loc = image::locator(current_data.image_diagonal, current_data.image_mod);
518  }
519 
520  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
521  image_loc = image::locator(current_data.image, current_data.image_mod);
522  }
523 
524  texture image;
525  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
526  image = image::get_texture(image_loc /*, image::SCALED_TO_ZOOM*/);
527  }
528 
529  const int d2 = display::get_singleton()->hex_size() / 2;
530 
531  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc) + d2;
532  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc) + d2;
533 
534  if(image != nullptr) {
535  bool facing_west = (
536  direction == map_location::NORTH_WEST ||
537  direction == map_location::SOUTH_WEST);
538 
539  bool facing_north = (
540  direction == map_location::NORTH_WEST ||
541  direction == map_location::NORTH ||
542  direction == map_location::NORTH_EAST);
543 
544  if(!current_data.auto_hflip) { facing_west = false; }
545  if(!current_data.auto_vflip) { facing_north = true; }
546 
547  const texture::info info = image.get_info();
548 
549  int my_x = x + current_data.x - ((info.w / 2) * game_disp->get_zoom_factor());
550  int my_y = y + current_data.y - ((info.h / 2) * game_disp->get_zoom_factor());
551 
552  if(facing_west) {
553  my_x -= current_data.directional_x;
554  } else {
555  my_x += current_data.directional_x;
556  }
557 
558  if(facing_north) {
559  my_y += current_data.directional_y;
560  } else {
561  my_y -= current_data.directional_y;
562  }
563 
564  //
565  // Begin unit drawing routine.
566  //
567 
568  fixed_t alpha = ftofxp(current_data.highlight_ratio);
569 
570  // Explicitly set sprite to opaque if not applying an alpha effect. This ensures that
571  // multiple copies of the same sprite - ie, diffent units of the same type - don't all
572  // get drawn with the alpha effect. This happened because they all use the same texture
573  // and setting the alpha mod on one affects them all.
574  set_texture_alpha(image, alpha < ftofxp(1.0) ? alpha : ALPHA_OPAQUE);
575 
576 #if 0
577  surface surf(image);
578 
579  color_t blend_to = current_data.blend_with ? *current_data.blend_with : color_t();
580 
581  if(current_data.blend_ratio != 0) {
582  surf = blend_surface(surf, current_data.blend_ratio, blend_to);
583  }
584 
585  if(alpha > ftofxp(1.0)) {
586  surf = brighten_image(surf, alpha);
587  //} else if(alpha != 1.0 && blendto != 0) {
588  // surf.assign(blend_surface(surf,1.0-alpha,blendto));
589  } else if(alpha != ftofxp(1.0)) {
590  surface temp = make_neutral_surface(surf);
591  adjust_surface_alpha(temp, alpha);
592  surf = temp;
593  }
594 
595  if(surf == nullptr) {
596  ERR_DP << "surface lost..." << std::endl;
597  return;
598  }
599 
600  if(current_data.submerge > 0.0) {
601  // Divide the surface into 2 parts
602  const int submerge_height = std::max<int>(0, surf->h*(1.0-current_data.submerge));
603  const int depth = surf->h - submerge_height;
604 
605  SDL_Rect srcrect {0, 0, surf->w, submerge_height};
606 
607  //drawing_queue_add(layer, loc, x, y, surf, srcrect);
608 
609  if(submerge_height != surf->h) {
610  //the lower part will be transparent
611  float alpha_base = 0.3f; // 30% alpha at surface of water
612  float alpha_delta = 0.015f; // lose 1.5% per pixel depth
613  alpha_delta *= zoom_ / DefaultZoom; // adjust with zoom
614  surf = submerge_alpha(surf, depth, alpha_base, alpha_delta);
615 
616  srcrect.y = submerge_height;
617  srcrect.h = surf->h-submerge_height;
618  y += submerge_height;
619 
620  //drawing_queue_add(layer, loc, x, y, surf, srcrect);
621  }
622  }
623 #endif
624 
625  game_disp->render_scaled_to_zoom(image, my_x, my_y, facing_west, !facing_north);
626  }
627 
628  halo_id.reset();
629 
630  if(!in_scope_of_frame) { //check after frame as first/last frame image used in defense/attack anims
631  return;
632  }
633 
634  // No halos, exit
635  if(current_data.halo.empty()) {
636  return;
637  }
638 
639  halo::ORIENTATION orientation;
640  switch(direction)
641  {
642  case map_location::NORTH:
644  orientation = halo::NORMAL;
645  break;
647  case map_location::SOUTH:
648  if(!current_data.auto_vflip) {
649  orientation = halo::NORMAL;
650  } else {
651  orientation = halo::VREVERSE;
652  }
653  break;
655  if(!current_data.auto_vflip) {
656  orientation = halo::HREVERSE;
657  } else {
658  orientation = halo::HVREVERSE;
659  }
660  break;
662  orientation = halo::HREVERSE;
663  break;
665  default:
666  orientation = halo::NORMAL;
667  break;
668  }
669 
670  if(direction != map_location::SOUTH_WEST && direction != map_location::NORTH_WEST) {
671  halo_id = halo_man.add(
672  static_cast<int>(x + current_data.halo_x * display::get_singleton()->get_zoom_factor()),
673  static_cast<int>(y + current_data.halo_y * display::get_singleton()->get_zoom_factor()),
674  current_data.halo + current_data.halo_mod,
675  map_location(-1, -1),
676  orientation
677  );
678  } else {
679  halo_id = halo_man.add(
680  static_cast<int>(x - current_data.halo_x * display::get_singleton()->get_zoom_factor()),
681  static_cast<int>(y + current_data.halo_y * display::get_singleton()->get_zoom_factor()),
682  current_data.halo + current_data.halo_mod,
683  map_location(-1, -1),
684  orientation
685  );
686  }
687 }
688 
689 std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time, const map_location& src, const map_location& dst,
690  const frame_parameters& animation_val, const frame_parameters& engine_val) const
691 {
693 
694  const int xsrc = disp->get_location_x(src);
695  const int ysrc = disp->get_location_y(src);
696  const int xdst = disp->get_location_x(dst);
697  const int ydst = disp->get_location_y(dst);
698  const map_location::DIRECTION direction = src.get_relative_dir(dst);
699 
700  const frame_parameters current_data = merge_parameters(frame_time, animation_val, engine_val);
701 
702  double tmp_offset = current_data.offset;
703  const int d2 = display::get_singleton()->hex_size() / 2;
704 
705  image::locator image_loc;
706  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
707  image_loc = image::locator(current_data.image_diagonal, current_data.image_mod);
708  }
709 
710  if(image_loc.is_void() || image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
711  image_loc = image::locator(current_data.image, current_data.image_mod);
712  }
713 
714  // We always invalidate our own hex because we need to be called at redraw time even
715  // if we don't draw anything in the hex itself
716  std::set<map_location> result;
717  if(tmp_offset == 0 && current_data.x == 0 && current_data.directional_x == 0 && image::is_in_hex(image_loc)) {
718  result.insert(src);
719 
720  bool facing_north = (
721  direction == map_location::NORTH_WEST ||
722  direction == map_location::NORTH ||
723  direction == map_location::NORTH_EAST);
724 
725  if(!current_data.auto_vflip) { facing_north = true; }
726 
727  int my_y = current_data.y;
728  if(facing_north) {
729  my_y += current_data.directional_y;
730  } else {
731  my_y -= current_data.directional_y;
732  }
733 
734  if(my_y < 0) {
735  result.insert(src.get_direction(map_location::NORTH));
736  result.insert(src.get_direction(map_location::NORTH_EAST));
737  result.insert(src.get_direction(map_location::NORTH_WEST));
738  } else if(my_y > 0) {
739  result.insert(src.get_direction(map_location::SOUTH));
740  result.insert(src.get_direction(map_location::SOUTH_EAST));
741  result.insert(src.get_direction(map_location::SOUTH_WEST));
742  }
743  } else {
744  int w = 0, h = 0;
745 
746  {
747  surface image;
748  if(!image_loc.is_void() && !image_loc.get_filename().empty()) { // invalid diag image, or not diagonal
749  image = image::get_image(image_loc, image::SCALED_TO_ZOOM);
750  }
751 
752  if(image != nullptr) {
753  w = image->w;
754  h = image->h;
755  }
756  }
757 
758  if(w != 0 || h != 0) {
759  const int x = static_cast<int>(tmp_offset * xdst + (1.0 - tmp_offset) * xsrc);
760  const int y = static_cast<int>(tmp_offset * ydst + (1.0 - tmp_offset) * ysrc);
761 
762  bool facing_west = (
763  direction == map_location::NORTH_WEST ||
764  direction == map_location::SOUTH_WEST);
765 
766  bool facing_north = (
767  direction == map_location::NORTH_WEST ||
768  direction == map_location::NORTH ||
769  direction == map_location::NORTH_EAST);
770 
771  if(!current_data.auto_vflip) { facing_north = true; }
772  if(!current_data.auto_hflip) { facing_west = false; }
773 
774  int my_x = x + current_data.x + d2 - w / 2;
775  int my_y = y + current_data.y + d2 - h / 2;
776 
777  if(facing_west) {
778  my_x += current_data.directional_x;
779  } else {
780  my_x -= current_data.directional_x;
781  }
782 
783  if(facing_north) {
784  my_y += current_data.directional_y;
785  } else {
786  my_y -= current_data.directional_y;
787  }
788 
789  // Check if our underlying hexes are invalidated. If we need to update ourselves because we changed,
790  // invalidate our hexes and return whether or not was successful.
791  const SDL_Rect r {my_x, my_y, w, h};
792  rect_of_hexes underlying_hex = disp->hexes_under_rect(r);
793 
794  result.insert(src);
795  result.insert(underlying_hex.begin(), underlying_hex.end());
796  } else {
797  // We have no "redraw surface" but we still need to invalidate our own hex in case we have a halo
798  // and/or sound that needs a redraw.
799  result.insert(src);
800  result.insert(dst);
801  }
802  }
803 
804  return result;
805 }
806 
807 /**
808  * This function merges the value provided by:
809  * - the frame
810  * - the engine (poison, flying unit...)
811  * - the animation as a whole
812  *
813  * There is no absolute rule for merging, so creativity is the rule. If a value is never provided by the engine, assert.
814  * This way if it becomes used, people will easily find the right place to look.
815  */
816 const frame_parameters unit_frame::merge_parameters(int current_time, const frame_parameters& animation_val,
817  const frame_parameters& engine_val) const
818 {
819  frame_parameters result;
820  const frame_parameters& current_val = builder_.parameters(current_time);
821 
822  result.primary_frame = engine_val.primary_frame;
823  if(!boost::logic::indeterminate(animation_val.primary_frame)) {
824  result.primary_frame = animation_val.primary_frame;
825  }
826 
827  if(!boost::logic::indeterminate(current_val.primary_frame)) {
828  result.primary_frame = current_val.primary_frame;
829  }
830 
831  // Convert the tribool to bool
832  const bool primary = result.primary_frame == true || boost::logic::indeterminate(result.primary_frame);
833 
834  /** The engine provides a default image to use for the unit when none is available */
835  result.image = current_val.image.is_void() || current_val.image.get_filename().empty()
836  ? animation_val.image
837  : current_val.image;
838 
839  if(primary && (result.image.is_void() || result.image.get_filename().empty())) {
840  result.image = engine_val.image;
841  }
842 
843  /** The engine provides a default image to use for the unit when none is available */
844  result.image_diagonal = current_val.image_diagonal.is_void() || current_val.image_diagonal.get_filename().empty()
845  ? animation_val.image_diagonal
846  : current_val.image_diagonal;
847 
848  if(primary && (result.image_diagonal.is_void() || result.image_diagonal.get_filename().empty())) {
849  result.image_diagonal = engine_val.image_diagonal;
850  }
851 
852  /**
853  * The engine provides a string for "petrified" and "team color" modifications.
854  * Note that image_mod is the complete modification and halo_mod is only the TC part.
855  */
856  result.image_mod = current_val.image_mod + animation_val.image_mod;
857  if(primary) {
858  result.image_mod += engine_val.image_mod;
859  } else {
860  result.image_mod += engine_val.halo_mod;
861  }
862 
863  assert(engine_val.halo.empty());
864  result.halo = current_val.halo.empty() ? animation_val.halo : current_val.halo;
865 
866  assert(engine_val.halo_x == 0);
867  result.halo_x = current_val.halo_x ? current_val.halo_x : animation_val.halo_x;
868 
869  /** The engine provides a y modification for terrain with height adjust and flying units */
870  result.halo_y = current_val.halo_y ? current_val.halo_y : animation_val.halo_y;
871  result.halo_y += engine_val.halo_y;
872 
873  result.halo_mod = current_val.halo_mod + animation_val.halo_mod;
874  result.halo_mod += engine_val.halo_mod;
875 
876  assert(engine_val.duration == 0);
877  result.duration = current_val.duration;
878 
879  assert(engine_val.sound.empty());
880  result.sound = current_val.sound.empty() ? animation_val.sound : current_val.sound;
881 
882  assert(engine_val.text.empty());
883  result.text = current_val.text.empty() ? animation_val.text : current_val.text;
884 
885  assert(!engine_val.text_color);
886  result.text_color = current_val.text_color ? current_val.text_color : animation_val.text_color;
887 
888  /** The engine provides a blend color for poisoned units */
889  result.blend_with = current_val.blend_with ? current_val.blend_with : animation_val.blend_with;
890  if(primary && engine_val.blend_with) {
891  result.blend_with = engine_val.blend_with->blend_lighten(result.blend_with ? *result.blend_with : color_t(0,0,0));
892  }
893 
894  /** The engine provides a blend color for poisoned units */
895  result.blend_ratio = current_val.blend_ratio?current_val.blend_ratio:animation_val.blend_ratio;
896  if(primary && engine_val.blend_ratio) {
897  result.blend_ratio = std::min(result.blend_ratio + engine_val.blend_ratio, 1.0);
898  }
899 
900  /** The engine provides a highlight ratio for selected units and visible "invisible" units */
901  result.highlight_ratio = (current_val.highlight_ratio < 0.999 || current_val.highlight_ratio > 1.001) ?
902  current_val.highlight_ratio : animation_val.highlight_ratio;
903  if(primary && (engine_val.highlight_ratio < 0.999 || engine_val.highlight_ratio > 1.001)) {
904  result.highlight_ratio = result.highlight_ratio * engine_val.highlight_ratio; // selected unit
905  }
906 
907  assert(engine_val.offset == 0);
908  result.offset = (current_val.offset != -1000) ? current_val.offset : animation_val.offset;
909  if(result.offset == -1000) {
910  result.offset = 0.0;
911  }
912 
913  /** The engine provides a submerge for units in water */
914  result.submerge = current_val.submerge ? current_val.submerge : animation_val.submerge;
915  if(primary && engine_val.submerge && !result.submerge) {
916  result.submerge = engine_val.submerge;
917  }
918 
919  assert(engine_val.x == 0);
920  result.x = current_val.x ? current_val.x : animation_val.x;
921 
922  /** The engine provides a y modification for terrain with height adjust and flying units */
923  result.y = current_val.y?current_val.y:animation_val.y;
924  result.y += engine_val.y;
925 
926  assert(engine_val.directional_x == 0);
927  result.directional_x = current_val.directional_x ? current_val.directional_x : animation_val.directional_x;
928 
929  assert(engine_val.directional_y == 0);
930  result.directional_y = current_val.directional_y ? current_val.directional_y : animation_val.directional_y;
931 
934  ? current_val.layer
935  : animation_val.layer;
936 
937  /** The engine provides us with a default value to compare to. Update if different */
938  result.auto_hflip = engine_val.auto_hflip;
939 
940  if(!boost::logic::indeterminate(animation_val.auto_hflip)) {
941  result.auto_hflip = animation_val.auto_hflip;
942  }
943 
944  if(!boost::logic::indeterminate(current_val.auto_hflip)) {
945  result.auto_hflip = current_val.auto_hflip;
946  }
947 
948  if(boost::logic::indeterminate(result.auto_hflip)) {
949  result.auto_hflip = true;
950  }
951 
952  result.auto_vflip = engine_val.auto_vflip;
953 
954  if(!boost::logic::indeterminate(animation_val.auto_vflip)) {
955  result.auto_vflip = animation_val.auto_vflip;
956  }
957 
958  if(!boost::logic::indeterminate(current_val.auto_vflip)) {
959  result.auto_vflip = current_val.auto_vflip;
960  }
961 
962  if(boost::logic::indeterminate(result.auto_vflip)) {
963  result.auto_vflip = !primary;
964  }
965 
966  return result;
967 }
const frame_parameters parameters(int current_time) const
Getters for the different parameters.
Definition: frame.cpp:298
Reserve layers to be selected for WML.
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:947
virtual const T get_current_element(int current_time, T default_val=T()) const override
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:689
std::string image_
Definition: frame.hpp:108
frame_builder & y(const std::string &y)
Definition: frame.cpp:205
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:99
progressive_int halo_x_
Definition: frame.hpp:173
progressive_single< image::locator > progressive_image
progressive_double blend_ratio_
Definition: frame.hpp:183
#define DefaultZoom
Definition: display.cpp:63
frame_parsed_parameters(const frame_builder &builder=frame_builder(), int override_duration=0)
Definition: frame.cpp:247
frame_builder & blend(const std::string &blend_ratio, const color_t blend_color)
Definition: frame.cpp:174
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:321
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
std::string text_
Definition: frame.hpp:116
bool has_attribute(config_key_type key) const
Definition: config.cpp:217
logger & info()
Definition: log.cpp:90
boost::optional< color_t > text_color
Definition: frame.hpp:53
Frame for unit&#39;s animation sequence.
frame_builder()
Definition: frame.cpp:45
iterator begin() const
Definition: hex_rect.hpp:100
int directional_x
Definition: frame.hpp:63
frame_builder & image_diagonal(const std::string &image_diagonal, const std::string &image_mod="")
Definition: frame.cpp:139
surface surf
Image.
progressive_int layer_
Definition: frame.hpp:196
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:695
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
frame_builder & directional_x(const std::string &directional_x)
Definition: frame.cpp:211
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:328
frame_builder & image(const std::string &image, const std::string &image_mod="")
Definition: frame.cpp:132
image::locator image_diagonal
Definition: frame.hpp:41
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:26
boost::tribool primary_frame_
Definition: frame.hpp:132
std::string halo
Definition: frame.hpp:44
std::string halo_
Definition: frame.hpp:111
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 & layer(const std::string &layer)
Definition: frame.cpp:241
frame_builder & submerge(const std::string &submerge)
Definition: frame.cpp:193
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:229
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:146
std::string halo_mod
Definition: frame.hpp:49
surface submerge_alpha(const surface &surf, int depth, float alpha_base, float alpha_delta)
Progressively reduce alpha of bottom part of the surface.
Definition: utils.cpp:1337
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
void set_texture_alpha(texture &t, uint8_t amount)
frame_builder & auto_vflip(const bool auto_vflip)
Definition: frame.cpp:223
Rectangular area of hexes.
Definition: hex_rect.hpp:33
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
int32_t fixed_t
Definition: math.hpp:292
std::string directional_x_
Definition: frame.hpp:127
std::vector< std::string > debug_strings() const
Contents of frame in strings.
Definition: frame.cpp:380
surface blend_surface(const surface &surf, const double amount, const color_t color)
Blends a surface with a color.
Definition: utils.cpp:1805
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:299
#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.
std::string layer_
Definition: frame.hpp:134
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
surface brighten_image(const surface &surf, fixed_t amount)
Definition: utils.cpp:1133
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:483
surface make_neutral_surface(const surface &surf)
Definition: utils.cpp:73
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
void render_scaled_to_zoom(const texture &tex, const int x_pos, const int y_pos, T &&... extra_args) const
Renders a texture directly to the screen (or current rendering target) scaled to the current zoom fac...
Definition: display.hpp:743
std::string image_mod
Definition: frame.hpp:43
int get_location_y(const map_location &loc) const
Definition: display.cpp:624
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:187
bool need_update() const
Definition: frame.cpp:293
frame_builder & x(const std::string &x)
Definition: frame.cpp:199
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
default layer for drawing units
int w
double get_zoom_factor() const
Returns the current zoom factor.
Definition: display.hpp:327
const std::string & get_filename() const
Definition: picture.hpp:86
frame_builder & primary_frame(const bool primary_frame)
Definition: frame.cpp:235
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:1078
const info get_info() const
Queries metadata about the texture, such as its dimensions.
Definition: texture.hpp:55
frame_builder & directional_y(const std::string &directional_y)
Definition: frame.cpp:217
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:619
#define ERR_NG
Definition: frame.cpp:25
ORIENTATION
Definition: halo.hpp:35
const uint8_t ALPHA_OPAQUE
Definition: color.hpp:48
progressive_int directional_y_
Definition: frame.hpp:190
void adjust_surface_alpha(surface &surf, fixed_t amount)
Definition: utils.cpp:1175
iterator end() const
Definition: hex_rect.hpp:105
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:168
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:181
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:97
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:68
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
#define ERR_DP
frame_builder & text(const std::string &text, const color_t text_color)
Definition: frame.cpp:152
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:274
Small wrapper that queries metadata about the provided texture.
Definition: texture.hpp:44
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:159
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:816
texture get_texture(const image::locator &i_locator, TYPE type)
Definition: picture.cpp:1424
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
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:555