The Battle for Wesnoth  1.19.2+dev
animation_component.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2024
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
17 
18 #include "config.hpp"
19 #include "display.hpp"
20 #include "map/map.hpp"
22 #include "random.hpp"
23 #include "units/unit.hpp"
24 #include "units/types.hpp"
25 
26 #include <set>
27 
28 namespace
29 {
30 int get_next_idle_time()
31 {
32  if(!prefs::get().idle_anim()) {
33  return std::numeric_limits<int>::max();
34  }
35 
36  const double rate = std::pow(2.0, -prefs::get().idle_anim_rate() / 10.0);
38  + static_cast<int>(randomness::rng::default_instance().get_random_int(20000, 39999) * rate);
39 }
40 } // namespace
41 
42 const unit_animation* unit_animation_component::choose_animation(const map_location& loc,const std::string& event,
43  const map_location& second_loc,const int value,const strike_result::type hit,
44  const_attack_ptr attack, const_attack_ptr second_attack, int swing_num)
45 {
46  // Select one of the matching animations at random
47  std::vector<const unit_animation*> options;
48  int max_val = unit_animation::MATCH_FAIL;
49  for(const unit_animation& anim : animations_) {
50  int matching = anim.matches(loc,second_loc,u_.shared_from_this(),event,value,hit,attack,second_attack,swing_num);
51  if(matching > unit_animation::MATCH_FAIL && matching == max_val) {
52  options.push_back(&anim);
53  } else if(matching > max_val) {
54  max_val = matching;
55  options.clear();
56  options.push_back(&anim);
57  }
58  }
59 
60  if(max_val == unit_animation::MATCH_FAIL) {
61  return nullptr;
62  }
63  return options[randomness::rng::default_instance().get_random_int(0, options.size()-1)];
64 }
65 
67 {
68  if (prefs::get().show_standing_animations()&& !u_.incapacitated()) {
69  start_animation(std::numeric_limits<int>::max(), choose_animation(u_.loc_, "standing"),
70  with_bars, "", {0,0,0}, STATE_STANDING);
71  } else {
72  start_animation(std::numeric_limits<int>::max(), choose_animation(u_.loc_, "_disabled_"),
73  with_bars, "", {0,0,0}, STATE_STANDING);
74  }
75 }
76 
78 {
79  start_animation(std::numeric_limits<int>::max(), choose_animation(u_.loc_, "_ghosted_"),
80  with_bars);
81  anim_->pause_animation();
82 }
83 
85 {
86  start_animation(std::numeric_limits<int>::max(), choose_animation(u_.loc_, "_disabled_ghosted_"),
87  with_bars);
88 }
89 
91 {
92  start_animation(std::numeric_limits<int>::max(), choose_animation(u_.loc_, "idling"),
93  true, "", {0,0,0}, STATE_FORGET);
94 }
95 
97 {
98  if (prefs::get().show_standing_animations() && !u_.incapacitated()) {
99  start_animation(std::numeric_limits<int>::max(), choose_animation(u_.loc_, "selected"),
100  true, "", {0,0,0}, STATE_FORGET);
101  } else {
102  start_animation(std::numeric_limits<int>::max(), choose_animation(u_.loc_, "_disabled_selected_"),
103  true, "", {0,0,0}, STATE_FORGET);
104  }
105 }
106 
107 void unit_animation_component::start_animation (int start_time, const unit_animation *animation,
108  bool with_bars, const std::string &text, color_t text_color, STATE state)
109 {
110  if (!animation) {
111  if (state == STATE_STANDING)
112  state_ = state;
113  if (!anim_ && state_ != STATE_STANDING)
114  set_standing(with_bars);
115  return ;
116  }
117  state_ = state;
118  // everything except standing select and idle
119  bool accelerate = (state != STATE_FORGET && state != STATE_STANDING);
120  draw_bars_ = with_bars;
121  anim_.reset(new unit_animation(*animation));
122  const int real_start_time = start_time == std::numeric_limits<int>::max() ? anim_->get_begin_time() : start_time;
123  anim_->start_animation(real_start_time, u_.loc_, u_.loc_.get_direction(u_.facing_),
124  text, text_color, accelerate);
125  frame_begin_time_ = anim_->get_begin_time() -1;
126  next_idling_ = get_next_idle_time();
127 }
128 
130 {
131  if (state_ == STATE_FORGET && anim_ && anim_->animation_finished_potential())
132  {
133  set_standing();
134  return;
135  }
136  display &disp = *display::get_singleton();
139  {
140  return;
141  }
143  {
144  // prevent all units animating at the same time
145  next_idling_ = get_next_idle_time();
146  } else {
147  set_idling();
148  }
149 }
150 
152 {
153  unit_halo_.reset();
154  abil_halos_.clear();
155  abil_halos_ref_.clear();
156  if(anim_ ) anim_->clear_haloes();
157 }
158 
160 {
161  bool result = false;
162 
163  // Very early calls, anim not initialized yet
164  if(get_animation()) {
165  frame_parameters params;
166  const gamemap & map = disp.get_map();
167  const t_translation::terrain_code terrain = map.get_terrain(u_.loc_);
168  const terrain_type& terrain_info = map.get_terrain_info(terrain);
169 
170  int height_adjust = static_cast<int>(terrain_info.unit_height_adjust() * disp.get_zoom_factor());
171  if (u_.is_flying() && height_adjust < 0) {
172  height_adjust = 0;
173  }
174  params.y -= height_adjust;
175  params.halo_y -= height_adjust;
176  params.image_mod = u_.image_mods();
177  params.halo_mod = u_.TC_image_mods();
178  params.image= u_.default_anim_image();
179 
180  result |= get_animation()->invalidate(params);
181  }
182 
183  return result;
184 
185 }
186 
188 {
189  if (newtype) {
190  animations_ = newtype->animations();
191  }
192 
193  refreshing_ = false;
194  anim_.reset();
195 }
196 
198  if(effect["id"].empty()) {
200  } else {
201  static std::map< std::string, std::vector<unit_animation>> animation_cache;
202  std::vector<unit_animation> &built = animation_cache[effect["id"]];
203  if(built.empty()) {
204  unit_animation::add_anims(built, effect);
205  }
206  animations_.insert(animations_.end(),built.begin(),built.end());
207  }
208 }
209 
210 std::vector<std::string> unit_animation_component::get_flags() {
211  std::set<std::string> result;
212  for(const auto& anim : animations_) {
213  const std::vector<std::string>& flags = anim.get_flags();
214  std::copy_if(flags.begin(), flags.end(), std::inserter(result, result.begin()), [](const std::string flag) {
215  return !(flag.empty() || (flag.front() == '_' && flag.back() == '_'));
216  });
217  }
218  return std::vector<std::string>(result.begin(), result.end());
219 }
int get_current_animation_tick()
Definition: animated.cpp:36
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:88
static double get_zoom_factor()
Returns the current zoom factor.
Definition: display.hpp:268
const gamemap & get_map() const
Definition: display.hpp:106
bool tile_nearly_on_screen(const map_location &loc) const
Checks if location loc or one of the adjacent tiles is visible on screen.
Definition: display.cpp:1933
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:102
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:301
Encapsulates the map of the game.
Definition: map.hpp:172
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:97
static prefs & get()
static rng & default_instance()
Definition: random.cpp:73
int get_random_int(int min, int max)
Definition: random.hpp:51
int unit_height_adjust() const
Definition: terrain.hpp:137
void set_idling()
Sets the animation state to idling.
bool draw_bars_
bool indicating whether to draw bars with the unit
std::vector< halo::handle > abil_halos_
handle to the abilities halos of this unit
const unit_animation * choose_animation(const map_location &loc, const std::string &event, const map_location &second_loc=map_location::null_location(), const int damage=0, const strike_result::type hit_type=strike_result::type::invalid, const_attack_ptr attack=nullptr, const_attack_ptr second_attack=nullptr, int swing_num=0)
Chooses an appropriate animation from the list of known animations.
std::vector< unit_animation > animations_
List of registered animations for this unit.
void apply_new_animation_effect(const config &effect)
Adds an animation described by a config.
std::unique_ptr< unit_animation > anim_
The current animation.
halo::handle unit_halo_
handle to the halo of this unit
bool invalidate(const display &disp)
Invalidates an animation with respect to a display object, preparing it for redraw.
void set_ghosted(bool with_bars=true)
Sets the animation state to ghosted.
void refresh()
Intermittently activates the idling animations in place of the standing animations.
void reset_after_advance(const unit_type *newtype=nullptr)
Resets the animations list after the unit is advanced.
std::vector< std::string > get_flags()
Get the flags of all registered animations.
void set_standing(bool with_bars=true)
Sets the animation state to standing.
const unit & u_
A reference to the unit that owns this object.
void start_animation(int start_time, const unit_animation *animation, bool with_bars, const std::string &text="", color_t text_color={}, STATE state=STATE_ANIM)
Begin an animation.
int frame_begin_time_
time for the frame to begin
std::vector< std::string > abil_halos_ref_
vector used to check that halo_abilities vector isn't modified between each read
STATE
States for animation.
@ STATE_FORGET
anim must fit in a hex
void set_selecting()
Sets the animation state to that when the unit is selected.
int next_idling_
time for next idle animation
bool refreshing_
avoid infinite recursion.
void clear_haloes()
Clear the haloes associated to the unit.
unit_animation * get_animation() const
Get a pointer to the current animation.
void set_disabled_ghosted(bool with_bars=true)
Whiteboard related somehow.
bool invalidate(frame_parameters &value)
Definition: animation.cpp:1106
static void add_anims(std::vector< unit_animation > &animations, const config &cfg)
Definition: animation.cpp:628
A single unit type that the player may recruit.
Definition: types.hpp:43
const std::vector< unit_animation > & animations() const
Definition: types.cpp:534
map_display and display: classes which take care of displaying the map and game-data on the screen.
map_location::DIRECTION facing_
Definition: unit.hpp:2019
map_location loc_
Definition: unit.hpp:1941
bool incapacitated() const
Check if the unit has been petrified.
Definition: unit.hpp:905
std::string TC_image_mods() const
Constructs a recolor (RC) IPF string for this unit's team color.
Definition: unit.cpp:2789
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition: unit.cpp:2794
std::string default_anim_image() const
The default image to use for animation frames with no defined image.
Definition: unit.cpp:2618
bool is_flying() const
Check if the unit is a flying unit.
Definition: unit.hpp:1507
std::shared_ptr< const attack_type > const_attack_ptr
Definition: ptr.hpp:34
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
All parameters from a frame at a given instant.
Definition: frame.hpp:36
std::string image_mod
Definition: frame.hpp:44
image::locator image
Definition: frame.hpp:41
std::string halo_mod
Definition: frame.hpp:50
Encapsulates the map of the game.
Definition: location.hpp:38
map_location get_direction(DIRECTION dir, unsigned int n=1u) const
Definition: location.cpp:359
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49