The Battle for Wesnoth  1.19.5+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 using namespace std::chrono_literals;
29 
30 namespace
31 {
32 std::chrono::steady_clock::time_point get_next_idle_tick()
33 {
34  if(!prefs::get().idle_anim()) {
35  return std::chrono::steady_clock::time_point::max();
36  }
37 
38  const double rate = std::pow(2.0, -prefs::get().idle_anim_rate() / 10.0);
39  const int duration = randomness::rng::default_instance().get_random_int(20000, 39999) * rate;
40  return get_current_animation_tick() + std::chrono::milliseconds{duration};
41 }
42 } // namespace
43 
44 const unit_animation* unit_animation_component::choose_animation(const map_location& loc,const std::string& event,
45  const map_location& second_loc,const int value,const strike_result::type hit,
46  const_attack_ptr attack, const_attack_ptr second_attack, int swing_num)
47 {
48  // Select one of the matching animations at random
49  std::vector<const unit_animation*> options;
50  int max_val = unit_animation::MATCH_FAIL;
51  for(const unit_animation& anim : animations_) {
52  int matching = anim.matches(loc,second_loc,u_.shared_from_this(),event,value,hit,attack,second_attack,swing_num);
53  if(matching > unit_animation::MATCH_FAIL && matching == max_val) {
54  options.push_back(&anim);
55  } else if(matching > max_val) {
56  max_val = matching;
57  options.clear();
58  options.push_back(&anim);
59  }
60  }
61 
62  if(max_val == unit_animation::MATCH_FAIL) {
63  return nullptr;
64  }
65  return options[randomness::rng::default_instance().get_random_int(0, options.size()-1)];
66 }
67 
69 {
70  if (prefs::get().show_standing_animations()&& !u_.incapacitated()) {
71  start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "standing"),
72  with_bars, "", {0,0,0}, STATE_STANDING);
73  } else {
74  start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "_disabled_"),
75  with_bars, "", {0,0,0}, STATE_STANDING);
76  }
77 }
78 
80 {
81  start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "_ghosted_"),
82  with_bars);
83  anim_->pause_animation();
84 }
85 
87 {
88  start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "_disabled_ghosted_"),
89  with_bars);
90 }
91 
93 {
94  start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "idling"),
95  true, "", {0,0,0}, STATE_FORGET);
96 }
97 
99 {
100  if (prefs::get().show_standing_animations() && !u_.incapacitated()) {
101  start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "selected"),
102  true, "", {0,0,0}, STATE_FORGET);
103  } else {
104  start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "_disabled_selected_"),
105  true, "", {0,0,0}, STATE_FORGET);
106  }
107 }
108 
109 void unit_animation_component::start_animation(const std::chrono::milliseconds& start_time, const unit_animation *animation,
110  bool with_bars, const std::string &text, color_t text_color, STATE state)
111 {
112  if (!animation) {
113  if (state == STATE_STANDING)
114  state_ = state;
115  if (!anim_ && state_ != STATE_STANDING)
116  set_standing(with_bars);
117  return ;
118  }
119  state_ = state;
120  // everything except standing select and idle
121  bool accelerate = (state != STATE_FORGET && state != STATE_STANDING);
122  draw_bars_ = with_bars;
123  anim_.reset(new unit_animation(*animation));
124  const auto real_start_time = start_time == std::chrono::milliseconds::max() ? anim_->get_begin_time() : start_time;
125  anim_->start_animation(real_start_time, u_.loc_, u_.loc_.get_direction(u_.facing_),
126  text, text_color, accelerate);
127  frame_begin_time_ = anim_->get_begin_time() - 1ms;
128  next_idling_ = get_next_idle_tick();
129 }
130 
132 {
133  if (state_ == STATE_FORGET && anim_ && anim_->animation_finished_potential())
134  {
135  set_standing();
136  return;
137  }
138  display &disp = *display::get_singleton();
139  if (state_ != STATE_STANDING || get_current_animation_tick() < next_idling_ ||
140  !disp.tile_nearly_on_screen(u_.loc_) || u_.incapacitated())
141  {
142  return;
143  }
144  if (get_current_animation_tick() > next_idling_ + 1000ms)
145  {
146  // prevent all units animating at the same time
147  next_idling_ = get_next_idle_tick();
148  } else {
149  set_idling();
150  }
151 }
152 
154 {
155  unit_halo_.reset();
156  abil_halos_.clear();
157  abil_halos_ref_.clear();
158  if(anim_ ) anim_->clear_haloes();
159 }
160 
162 {
163  bool result = false;
164 
165  // Very early calls, anim not initialized yet
166  if(get_animation()) {
167  frame_parameters params;
168  const gamemap& map = disp.context().map();
169  const t_translation::terrain_code terrain = map.get_terrain(u_.loc_);
170  const terrain_type& terrain_info = map.get_terrain_info(terrain);
171 
172  int height_adjust = static_cast<int>(terrain_info.unit_height_adjust() * disp.get_zoom_factor());
173  if (u_.is_flying() && height_adjust < 0) {
174  height_adjust = 0;
175  }
176  params.y -= height_adjust;
177  params.halo_y -= height_adjust;
178  params.image_mod = u_.image_mods();
179  params.halo_mod = u_.TC_image_mods();
180  params.image= u_.default_anim_image();
181 
182  result |= get_animation()->invalidate(params);
183  }
184 
185  return result;
186 
187 }
188 
190 {
191  if (newtype) {
192  animations_ = newtype->animations();
193  }
194 
195  refreshing_ = false;
196  anim_.reset();
197 }
198 
200  if(effect["id"].empty()) {
201  unit_animation::add_anims(animations_, effect);
202  } else {
203  static std::map< std::string, std::vector<unit_animation>> animation_cache;
204  std::vector<unit_animation> &built = animation_cache[effect["id"]];
205  if(built.empty()) {
206  unit_animation::add_anims(built, effect);
207  }
208  animations_.insert(animations_.end(),built.begin(),built.end());
209  }
210 }
211 
212 std::vector<std::string> unit_animation_component::get_flags() {
213  std::set<std::string> result;
214  for(const auto& anim : animations_) {
215  const std::vector<std::string>& flags = anim.get_flags();
216  std::copy_if(flags.begin(), flags.end(), std::inserter(result, result.begin()), [](const std::string flag) {
217  return !(flag.empty() || (flag.front() == '_' && flag.back() == '_'));
218  });
219  }
220  return std::vector<std::string>(result.begin(), result.end());
221 }
std::chrono::steady_clock::time_point get_current_animation_tick()
Definition: animated.cpp:34
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
virtual const gamemap & map() const =0
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:97
static double get_zoom_factor()
Returns the current zoom factor.
Definition: display.hpp:270
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:1888
const display_context & context() const
Definition: display.hpp:193
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:111
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:302
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:98
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.
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.
void apply_new_animation_effect(const config &effect)
Adds an animation described by a config.
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.
STATE
States for animation.
void set_selecting()
Sets the animation state to that when the unit is selected.
void clear_haloes()
Clear the haloes associated to the unit.
void set_disabled_ghosted(bool with_bars=true)
Whiteboard related somehow.
void start_animation(const std::chrono::milliseconds &start_time, const unit_animation *animation, bool with_bars, const std::string &text="", color_t text_color={}, STATE state=STATE_ANIM)
Begin an animation.
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:536
Definitions for the interface to Wesnoth Markup Language (WML).
map_display and display: classes which take care of displaying the map and game-data on the screen.
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:44
std::string image_mod
Definition: frame.hpp:50
image::locator image
Definition: frame.hpp:47
std::string halo_mod
Definition: frame.hpp:56
Encapsulates the map of the game.
Definition: location.hpp:45
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