The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
animation_component.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
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 "log.hpp"
21#include "random.hpp"
22#include "units/unit.hpp"
23#include "units/types.hpp"
24
25#include <set>
26
27static lg::log_domain log_engine("engine");
28#define ERR_NG LOG_STREAM(err, log_engine)
29
30using namespace std::chrono_literals;
31
32namespace
33{
34std::chrono::steady_clock::time_point get_next_idle_tick()
35{
36 if(!prefs::get().idle_anim()) {
37 return std::chrono::steady_clock::time_point::max();
38 }
39
40 const double rate = std::pow(2.0, -prefs::get().idle_anim_rate() / 10.0);
41 const int duration = randomness::rng::default_instance().get_random_int(20000, 39999) * rate;
42 return get_current_animation_tick(false) + std::chrono::milliseconds{duration};
43}
44} // namespace
45
47 const map_location& second_loc,const int value,const strike_result::type hit,
48 const const_attack_ptr& attack, const const_attack_ptr& second_attack, int swing_num)
49{
50 // Select one of the matching animations at random
51 std::vector<const unit_animation*> options;
52 int max_val = unit_animation::MATCH_FAIL;
53 for(const unit_animation& anim : animations_) {
54 int matching = anim.matches(loc,second_loc,u_.shared_from_this(),event,value,hit,attack,second_attack,swing_num);
55 if(matching > unit_animation::MATCH_FAIL && matching == max_val) {
56 options.push_back(&anim);
57 } else if(matching > max_val) {
58 max_val = matching;
59 options.clear();
60 options.push_back(&anim);
61 }
62 }
63
64 if(max_val == unit_animation::MATCH_FAIL) {
65 return nullptr;
66 }
67 return options[randomness::rng::default_instance().get_random_int(0, options.size()-1)];
68}
69
71{
72 if (prefs::get().show_standing_animations()&& !u_.incapacitated()) {
73 start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "standing"),
74 with_bars, "", {0,0,0}, STATE_STANDING);
75 } else {
76 start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "_disabled_"),
77 with_bars, "", {0,0,0}, STATE_STANDING);
78 }
79}
80
82{
83 start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "_ghosted_"),
84 with_bars);
85 anim_->pause_animation();
86}
87
89{
90 start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "_disabled_ghosted_"),
91 with_bars);
92}
93
95{
96 start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "idling"),
97 true, "", {0,0,0}, STATE_FORGET);
98}
99
101{
102 if (prefs::get().show_standing_animations() && !u_.incapacitated()) {
103 start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "selected"),
104 true, "", {0,0,0}, STATE_FORGET);
105 } else {
106 start_animation(std::chrono::milliseconds::max(), choose_animation(u_.loc_, "_disabled_selected_"),
107 true, "", {0,0,0}, STATE_FORGET);
108 }
109}
110
111void unit_animation_component::start_animation(const std::chrono::milliseconds& start_time, const unit_animation *animation,
112 bool with_bars, const std::string &text, color_t text_color, STATE state)
113{
114 if (!animation) {
115 if (state == STATE_STANDING)
116 state_ = state;
117 if (!anim_ && state_ != STATE_STANDING)
118 set_standing(with_bars);
119 return ;
120 }
121 state_ = state;
122 // everything except standing select and idle
123 bool accelerate = (state != STATE_FORGET && state != STATE_STANDING);
124 draw_bars_ = with_bars;
125 anim_.reset(new unit_animation(*animation));
126 const auto real_start_time = start_time == std::chrono::milliseconds::max() ? anim_->get_begin_time() : start_time;
127 anim_->start_animation(real_start_time, u_.loc_, u_.loc_.get_direction(u_.facing_),
128 text, text_color, accelerate);
129 frame_begin_time_ = anim_->get_begin_time() - 1ms;
130 next_idling_ = get_next_idle_tick();
131}
132
134{
135 if (state_ == STATE_FORGET && anim_ && anim_->animation_finished())
136 {
137 set_standing();
138 return;
139 }
143 {
144 return;
145 }
146 if (get_current_animation_tick(false) > next_idling_ + 1000ms)
147 {
148 // prevent all units animating at the same time
149 next_idling_ = get_next_idle_tick();
150 } else {
151 set_idling();
152 }
153}
154
156{
157 unit_halo_.reset();
158 abil_halos_.clear();
159 abil_halos_ref_.clear();
160 if(anim_ ) anim_->clear_haloes();
161}
162
164{
165 bool result = false;
166
167 // Very early calls, anim not initialized yet
168 if(get_animation()) {
169 frame_parameters params;
170 const gamemap& map = disp.context().map();
171 const terrain_type& terrain_info = map.get_terrain_info(u_.loc_);
172
173 int height_adjust = static_cast<int>(terrain_info.unit_height_adjust() * disp.get_zoom_factor());
174 if (u_.is_flying() && height_adjust < 0) {
175 height_adjust = 0;
176 }
177 params.y -= height_adjust;
178 params.halo_y -= height_adjust;
179 params.image_mod = u_.image_mods();
180 params.halo_mod = u_.TC_image_mods();
181 params.image= u_.default_anim_image();
182
183 result |= get_animation()->invalidate(params);
184 }
185
186 return result;
187
188}
189
191{
192 if (newtype) {
193 animations_ = newtype->animations();
194 }
195
196 refreshing_ = false;
197 anim_.reset();
198}
199
201{
203 for(const unit& unit : units) {
204 if(unit.incapacitated() || &unit == &u_) {
205 continue;
206 }
208 }
209 }
210}
211
213 if(effect["id"].empty()) {
215 } else {
216 static std::map< std::string, std::vector<unit_animation>> animation_cache;
217 std::vector<unit_animation> &built = animation_cache[effect["id"]];
218 if(built.empty()) {
219 unit_animation::add_anims(built, effect);
220 }
221 animations_.insert(animations_.end(),built.begin(),built.end());
222 }
223}
224
225std::vector<std::string> unit_animation_component::get_flags() {
226 std::set<std::string> result;
227 for(const auto& anim : animations_) {
228 const std::vector<std::string>& flags = anim.get_flags();
229 std::copy_if(flags.begin(), flags.end(), std::inserter(result, result.begin()), [](const std::string& flag) {
230 return !(flag.empty() || (flag.front() == '_' && flag.back() == '_'));
231 });
232 }
233 return std::vector<std::string>(result.begin(), result.end());
234}
map_location loc
Definition move.cpp:172
std::chrono::steady_clock::time_point get_current_animation_tick(bool uses_acceleration)
Gets the current time point for animations.
Definition animated.cpp:49
static lg::log_domain log_engine("engine")
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
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:88
static double get_zoom_factor()
Returns the current zoom factor.
Definition display.hpp:262
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:1728
static display * get_singleton()
Returns the display object if a display object exists.
Definition display.hpp:102
const display_context & context() const
Definition display.hpp:187
Encapsulates the map of the game.
Definition map.hpp:176
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition map.cpp:78
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:147
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
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.
unit_animation * get_animation() const
Get a pointer to the current animation.
void reset_after_advance(const unit_type *newtype=nullptr)
Resets the animations list after the unit is advanced.
void reset_affect_adjacent(const unit_map &units)
Refresh map around unit if has ability with [affect_adjacent/distant] tag.
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.
std::vector< std::string > abil_halos_ref_
vector used to check that halo_abilities vector isn't modified between each read
@ STATE_FORGET
anim must fit in a hex
void set_selecting()
Sets the animation state to that when the unit is selected.
bool refreshing_
avoid infinite recursion.
void clear_haloes()
Clear the haloes associated to the unit.
void set_disabled_ghosted(bool with_bars=true)
Whiteboard related somehow.
std::chrono::milliseconds frame_begin_time_
time for the frame to begin
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 const_attack_ptr &attack=nullptr, const const_attack_ptr &second_attack=nullptr, int swing_num=0)
Chooses an appropriate animation from the list of known animations.
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.
std::chrono::steady_clock::time_point next_idling_
time for next idle animation
bool invalidate(frame_parameters &value)
int matches(const map_location &loc, const map_location &second_loc, const unit_const_ptr &my_unit, const std::string &event="", const int value=0, strike_result::type hit=strike_result::type::invalid, const const_attack_ptr &attack=nullptr, const const_attack_ptr &second_attack=nullptr, int value2=0) const
static void add_anims(std::vector< unit_animation > &animations, const config &cfg)
Container associating units to locations.
Definition map.hpp:98
A single unit type that the player may recruit.
Definition types.hpp:43
const std::vector< unit_animation > & animations() const
Definition types.cpp:496
This class represents a single unit of a specific type.
Definition unit.hpp:39
Definitions for the interface to Wesnoth Markup Language (WML).
map_location::direction facing_
Definition unit.hpp:1918
map_location loc_
Definition unit.hpp:1840
bool incapacitated() const
Check if the unit has been petrified.
Definition unit.hpp:826
std::string TC_image_mods() const
Constructs a recolor (RC) IPF string for this unit's team color.
Definition unit.cpp:2793
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition unit.cpp:2798
std::string default_anim_image() const
The default image to use for animation frames with no defined image.
Definition unit.cpp:2622
unit_animation_component & anim_comp() const
Definition unit.hpp:1537
bool is_flying() const
Check if the unit is a flying unit.
Definition unit.hpp:1436
std::size_t max_ability_radius_image() const
If this unit has abilities with [affect_adjacent] subtags and halo_image or overlay_image attributes,...
Definition unit.hpp:1223
Standard logging facilities (interface).
std::shared_ptr< const attack_type > const_attack_ptr
Definition ptr.hpp:34
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
The basic class for representing 8-bit RGB or RGBA colour values.
Definition color.hpp:51
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:46
map_location get_direction(direction dir, unsigned int n=1u) const
Definition location.cpp:362