allow multiple sub-animations, in all animations (not just missile in fight)

This commit is contained in:
Jérémy Rosen 2007-10-28 10:17:53 +00:00
parent bdab825b22
commit dd48d3d8db
11 changed files with 257 additions and 114 deletions

View file

@ -41,6 +41,9 @@ Version 1.3.9+svn:
are now deleted (rather than just autosaves as formerly). This are now deleted (rather than just autosaves as formerly). This
is done before replay saving, if that is enabled. The preference is done before replay saving, if that is enabled. The preference
name has changed from delete_autosaves to delete_saves. name has changed from delete_autosaves to delete_saves.
* Animation engine allow multiple type of frames (a la "missile frames")
for all types of anims, you can have multiple such anims using different
frame names
* miscellaneous and bug fixes: * miscellaneous and bug fixes:
Version 1.3.9: Version 1.3.9:

View file

@ -112,6 +112,7 @@ private:
double acceleration_; double acceleration_;
int last_update_tick_; int last_update_tick_;
int current_frame_key_; int current_frame_key_;
int last_frame_key_;
}; };

View file

@ -51,7 +51,8 @@ animated<T,T_void_value>::animated(int start_time) :
cycles_(false), cycles_(false),
acceleration_(1), acceleration_(1),
last_update_tick_(0), last_update_tick_(0),
current_frame_key_(0) current_frame_key_(0),
last_frame_key_(-1)
{ {
} }
@ -64,7 +65,8 @@ animated<T,T_void_value>::animated(const std::vector<std::pair<int,T> > &cfg, in
cycles_(false), cycles_(false),
acceleration_(1), acceleration_(1),
last_update_tick_(0), last_update_tick_(0),
current_frame_key_(0) current_frame_key_(0),
last_frame_key_(-1)
{ {
typename std::vector< std::pair<int,T> >::const_iterator itor = cfg.begin(); typename std::vector< std::pair<int,T> >::const_iterator itor = cfg.begin();
@ -101,6 +103,8 @@ void animated<T,T_void_value>::start_animation(int start_time, bool cycles, doub
if(acceleration_ <=0) acceleration_ = 1; if(acceleration_ <=0) acceleration_ = 1;
current_frame_key_= 0; current_frame_key_= 0;
update_last_draw_time(); update_last_draw_time();
// need to force last frame key in the case of starting anim...
last_frame_key_ = -1;
} }
@ -108,6 +112,7 @@ template<typename T, typename T_void_value>
void animated<T,T_void_value>::update_last_draw_time() void animated<T,T_void_value>::update_last_draw_time()
{ {
last_update_tick_ = current_ticks; last_update_tick_ = current_ticks;
last_frame_key_ = current_frame_key_;
if(does_not_change_) if(does_not_change_)
return; return;
@ -124,6 +129,7 @@ void animated<T,T_void_value>::update_last_draw_time()
while(get_animation_time() > get_end_time()){ // cut extra time while(get_animation_time() > get_end_time()){ // cut extra time
start_tick_ += static_cast<int>(get_end_time()/acceleration_); start_tick_ += static_cast<int>(get_end_time()/acceleration_);
current_frame_key_ = 0; current_frame_key_ = 0;
last_frame_key_ = -1;
} }
} }
if(get_current_frame_end_time() < get_animation_time() && // catch up if(get_current_frame_end_time() < get_animation_time() && // catch up

View file

@ -829,8 +829,8 @@ void display::clear_hex_overlay(const gamemap::location& loc)
} }
void display::render_unit_image(int x, int y, surface image, void display::render_unit_image(int x, int y, surface image,
bool reverse, bool greyscale, fixed_t alpha, bool hreverse, bool greyscale, fixed_t alpha,
Uint32 blendto, double blend_ratio, double submerged) Uint32 blendto, double blend_ratio, double submerged,bool vreverse)
{ {
if (image==NULL) if (image==NULL)
@ -843,9 +843,12 @@ void display::render_unit_image(int x, int y, surface image,
surface surf(image); surface surf(image);
if(reverse) { if(hreverse) {
surf = image::reverse_image(surf); surf = image::reverse_image(surf);
} }
if(vreverse) {
surf = flop_surface(surf);
}
if(greyscale) { if(greyscale) {
surf = greyscale_image(surf); surf = greyscale_image(surf);

View file

@ -234,9 +234,9 @@ public:
//! submerged: the amount of the unit out of 1.0 that is submerged //! submerged: the amount of the unit out of 1.0 that is submerged
//! (presumably under water) and thus shouldn't be drawn //! (presumably under water) and thus shouldn't be drawn
void render_unit_image(int x, int y, surface image, void render_unit_image(int x, int y, surface image,
bool reverse=false, bool greyscale=false, bool hreverse=false, bool greyscale=false,
fixed_t alpha=ftofxp(1.0), Uint32 blendto=0, fixed_t alpha=ftofxp(1.0), Uint32 blendto=0,
double blend_ratio=0, double submerged=0.0); double blend_ratio=0, double submerged=0.0,bool vreverse =false);
const theme::menu* menu_pressed(); const theme::menu* menu_pressed();

View file

@ -1320,12 +1320,7 @@ void unit::read(const config& cfg, bool use_traits)
animations_ = ut->animations_; animations_ = ut->animations_;
cfg_.clear_children("animation"); cfg_.clear_children("animation");
} else { } else {
const config::child_list& animations = cfg_.get_children("animation"); unit_animation::initialize_anims(animations_,cfg_,type()->attacks(true));
config::child_list::const_iterator d;
for(d = animations.begin(); d != animations.end(); ++d) {
animations_.push_back(unit_animation(**d));
}
unit_animation::back_compat_initialize_anims(animations_,cfg_,type()->attacks(true));
} }
} else { } else {
// Remove animations from private cfg, since they're not needed there now // Remove animations from private cfg, since they're not needed there now
@ -1614,7 +1609,7 @@ void unit::start_animation(const game_display &disp, const gamemap::location &lo
offset_=0; offset_=0;
if(anim_) delete anim_; if(anim_) delete anim_;
anim_ = new unit_animation(*animation); anim_ = new unit_animation(*animation);
anim_->start_animation(anim_->get_begin_time(), cycles, disp.turbo_speed()); anim_->start_animation(anim_->get_begin_time(),loc, loc.get_direction(facing_), cycles, disp.turbo_speed());
frame_begin_time_ = anim_->get_begin_time() -1; frame_begin_time_ = anim_->get_begin_time() -1;
if (disp.idle_anim()) { if (disp.idle_anim()) {
next_idling_ = get_current_animation_tick() next_idling_ = get_current_animation_tick()
@ -1624,9 +1619,9 @@ void unit::start_animation(const game_display &disp, const gamemap::location &lo
} }
} }
void unit::restart_animation(const game_display& disp,int start_time) { void unit::restart_animation(const game_display& disp,int start_time, bool cycles) {
if(!anim_) return; if(!anim_) return;
anim_->start_animation(start_time,false,disp.turbo_speed()); anim_->start_animation(start_time,gamemap::location::null_location, gamemap::location::null_location, cycles, disp.turbo_speed());
frame_begin_time_ = start_time -1; frame_begin_time_ = start_time -1;
} }
@ -1868,6 +1863,7 @@ void unit::redraw_unit(game_display& disp, const gamemap::location& loc)
} }
} }
anim_->redraw();
refreshing_ = false; refreshing_ = false;
anim_->update_last_draw_time(); anim_->update_last_draw_time();
} }
@ -2590,13 +2586,7 @@ void unit::add_modification(const std::string& type, const config& mod, bool no_
game_config::add_color_info(**i.first); game_config::add_color_info(**i.first);
LOG_UT << "applying image_mod \n"; LOG_UT << "applying image_mod \n";
} else if (apply_to == "new_animation") { } else if (apply_to == "new_animation") {
// TODO most of this is to keep backward compatibility, to be removed in due time... unit_animation::initialize_anims(animations_,**i.first,std::vector<attack_type>());
const config::child_list& animations = (**i.first).get_children("animation");
config::child_list::const_iterator d;
for(d = animations.begin(); d != animations.end(); ++d) {
animations_.push_back(unit_animation(**d));
}
unit_animation::back_compat_initialize_anims(animations_,**i.first,std::vector<attack_type>());
} }
} // end while } // end while
} else { // for times = per level & level = 0 we still need to rebuild the descriptions } else { // for times = per level & level = 0 we still need to rebuild the descriptions

View file

@ -190,7 +190,7 @@ public:
void set_victorious(const game_display &disp,const gamemap::location& loc,const attack_type* attack,const attack_type* secondary_attack); void set_victorious(const game_display &disp,const gamemap::location& loc,const attack_type* attack,const attack_type* secondary_attack);
void set_poisoned(const game_display& disp,const gamemap::location& loc,int damage); void set_poisoned(const game_display& disp,const gamemap::location& loc,int damage);
void set_idling(const game_display& disp,const gamemap::location& loc); void set_idling(const game_display& disp,const gamemap::location& loc);
void restart_animation(const game_display& disp,int start_time); void restart_animation(const game_display& disp,int start_time, bool cycles = false);
const unit_animation* get_animation() const { return anim_;}; const unit_animation* get_animation() const { return anim_;};
void set_offset(double offset){offset_ = offset;} void set_offset(double offset){offset_ = offset;}
void set_facing(gamemap::location::DIRECTION dir); void set_facing(gamemap::location::DIRECTION dir);

View file

@ -19,12 +19,14 @@
#include "game_config.hpp" #include "game_config.hpp"
#include "gettext.hpp" #include "gettext.hpp"
#include "log.hpp" #include "log.hpp"
#include "halo.hpp"
#include "pathutils.hpp" #include "pathutils.hpp"
#include "unit.hpp" #include "unit.hpp"
#include "unit_animation.hpp" #include "unit_animation.hpp"
#include "unit_types.hpp" #include "unit_types.hpp"
#include "util.hpp" #include "util.hpp"
#include "variable.hpp" #include "variable.hpp"
#include "sound.hpp"
#include "wassert.hpp" #include "wassert.hpp"
#include "serialization/string_utils.hpp" #include "serialization/string_utils.hpp"
@ -104,8 +106,14 @@ unit_animation::unit_animation(int start_time,const unit_frame & frame , const s
unit_animation::unit_animation(const config& cfg,const std::string frame_string ) : unit_animation::unit_animation(const config& cfg,const std::string frame_string ) :
terrain_types_(t_translation::read_list(cfg["terrain"])),base_score_(0), terrain_types_(t_translation::read_list(cfg["terrain"])),base_score_(0),
missile_anim_(cfg,"missile_"),unit_anim_(cfg,frame_string) unit_anim_(cfg,frame_string)
{ {
config::child_map::const_iterator frame_itor =cfg.all_children().begin();
for( /*null*/; frame_itor != cfg.all_children().end() ; frame_itor++) {
if(frame_itor->first == frame_string) continue;
if(frame_itor->first.find("_frame",frame_itor->first.size() -6 ) == std::string::npos) continue;
sub_anims_[frame_itor->first] = crude_animation(cfg,frame_itor->first.substr(0,frame_itor->first.size() -5));
}
event_ =utils::split(cfg["apply_to"]); event_ =utils::split(cfg["apply_to"]);
const std::vector<std::string>& my_directions = utils::split(cfg["direction"]); const std::vector<std::string>& my_directions = utils::split(cfg["direction"]);
@ -266,10 +274,18 @@ void unit_animation::back_compat_add_name(const std::string name,const std::stri
} }
void unit_animation::back_compat_initialize_anims( std::vector<unit_animation> & animations, const config & cfg, std::vector<attack_type> tmp_attacks) void unit_animation::initialize_anims( std::vector<unit_animation> & animations, const config & cfg, std::vector<attack_type> tmp_attacks)
{ {
config expanded_cfg; config expanded_cfg;
config::child_list::const_iterator anim_itor; config::child_list::const_iterator anim_itor;
expanded_cfg = unit_animation::prepare_animation(cfg,"animation");
const config::child_list& parsed_animations = expanded_cfg.get_children("animation");
for(anim_itor = parsed_animations.begin(); anim_itor != parsed_animations.end(); ++anim_itor) {
animations.push_back(unit_animation(**anim_itor));
}
expanded_cfg = unit_animation::prepare_animation(cfg,"leading_anim"); expanded_cfg = unit_animation::prepare_animation(cfg,"leading_anim");
const config::child_list& leading_anims = expanded_cfg.get_children("leading_anim"); const config::child_list& leading_anims = expanded_cfg.get_children("leading_anim");
for(anim_itor = leading_anims.begin(); anim_itor != leading_anims.end(); ++anim_itor) { for(anim_itor = leading_anims.begin(); anim_itor != leading_anims.end(); ++anim_itor) {
@ -513,6 +529,10 @@ unit_animation::crude_animation::crude_animation(const config& cfg,const std::st
} else { } else {
starting_frame_time_ = atoi(cfg[frame_string+"start_time"].c_str()); starting_frame_time_ = atoi(cfg[frame_string+"start_time"].c_str());
} }
if(frame_string == "missile_") {
// lg::wml_error To be deprecated eventually
add_frame(1,unit_frame("",1),true);
}
for(; range.first != range.second; ++range.first) { for(; range.first != range.second; ++range.first) {
unit_frame tmp_frame(**range.first); unit_frame tmp_frame(**range.first);
@ -526,6 +546,14 @@ unit_animation::crude_animation::crude_animation(const config& cfg,const std::st
blend_ratio_ = progressive_double(cfg[frame_string+"blend_ratio"],get_animation_duration()); blend_ratio_ = progressive_double(cfg[frame_string+"blend_ratio"],get_animation_duration());
highlight_ratio_ = progressive_double(cfg[frame_string+"alpha"],get_animation_duration()); highlight_ratio_ = progressive_double(cfg[frame_string+"alpha"],get_animation_duration());
offset_ = progressive_double(cfg[frame_string+"offset"],get_animation_duration()); offset_ = progressive_double(cfg[frame_string+"offset"],get_animation_duration());
if(offset_.does_not_change() && frame_string == "missile_") {
// lg::wml_error To be deprecated eventually
offset_=progressive_double("0~0.8",get_animation_duration());
}
if( frame_string == "missile_") {
// lg::wml_error To be deprecated eventually
add_frame(1,unit_frame("",1),true);
}
if(!halo_.does_not_change() || if(!halo_.does_not_change() ||
!halo_x_.does_not_change() || !halo_x_.does_not_change() ||
@ -539,3 +567,166 @@ unit_animation::crude_animation::crude_animation(const config& cfg,const std::st
bool unit_animation::need_update() const
{
if(unit_anim_.need_update()) return true;
std::map<std::string,crude_animation>::const_iterator anim_itor =sub_anims_.begin();
for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
if(anim_itor->second.need_update()) return true;
}
return false;
};
bool unit_animation::animation_finished() const
{
if(!unit_anim_.animation_finished()) return false;
std::map<std::string,crude_animation>::const_iterator anim_itor =sub_anims_.begin();
for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
if(!anim_itor->second.animation_finished()) return false;
}
return true;
};
bool unit_animation::animation_would_finish() const
{
if(!unit_anim_.animation_would_finish()) return false;
std::map<std::string,crude_animation>::const_iterator anim_itor =sub_anims_.begin();
for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
if(!anim_itor->second.animation_would_finish()) return false;
}
return true;
};
void unit_animation::update_last_draw_time()
{
unit_anim_.update_last_draw_time();
std::map<std::string,crude_animation>::iterator anim_itor =sub_anims_.begin();
for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
anim_itor->second.update_last_draw_time();
}
};
int unit_animation::get_end_time() const
{
int result = unit_anim_.get_end_time();
std::map<std::string,crude_animation>::const_iterator anim_itor =sub_anims_.end();
for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
result= minimum<int>(result,anim_itor->second.get_end_time());
}
return result;
};
int unit_animation::get_begin_time() const
{
int result = unit_anim_.get_begin_time();
std::map<std::string,crude_animation>::const_iterator anim_itor =sub_anims_.begin();
for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
result= minimum<int>(result,anim_itor->second.get_begin_time());
}
return result;
};
void unit_animation::start_animation(int start_time,const gamemap::location &src, const gamemap::location &dst, bool cycles, double acceleration)
{
unit_anim_.start_animation(start_time, src, dst, cycles, acceleration);
std::map<std::string,crude_animation>::iterator anim_itor =sub_anims_.begin();
for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
anim_itor->second.start_animation(start_time,src,dst,cycles,acceleration);
}
}
void unit_animation::redraw()
{
std::map<std::string,crude_animation>::iterator anim_itor =sub_anims_.begin();
for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
anim_itor->second.redraw();
}
}
void unit_animation::crude_animation::redraw()
{
const int xsrc = game_display::get_singleton()->get_location_x(src_);
const int ysrc = game_display::get_singleton()->get_location_y(src_);
const int xdst = game_display::get_singleton()->get_location_x(dst_);
const int ydst = game_display::get_singleton()->get_location_y(dst_);
const gamemap::location::DIRECTION direction = src_.get_relative_dir(dst_);
double tmp_offset = offset();
int d2 = game_display::get_singleton()->hex_size() / 2;
const unit_frame& current_frame= get_current_frame();
if(!current_frame.sound().empty() && get_current_frame_begin_time() != last_frame_begin_time_ ) {
sound::play_sound(current_frame.sound());
}
last_frame_begin_time_ = get_current_frame_begin_time();
image::locator image_loc;
if(direction != gamemap::location::NORTH && direction != gamemap::location::SOUTH) {
image_loc = current_frame.image_diagonal();
}
if(image_loc.is_void()) { // invalid diag image, or not diagonal
image_loc = current_frame.image();
}
surface image;
if(!image_loc.is_void() && image_loc.get_filename() != "") { // invalid diag image, or not diagonal
image=image::get_image(image_loc,
image::SCALED_TO_ZOOM,
false
);
}
const int x = static_cast<int>(tmp_offset * xdst + (1.0-tmp_offset) * xsrc) + d2 ;
const int y = static_cast<int>(tmp_offset * ydst + (1.0-tmp_offset) * ysrc) + d2;
if (image != NULL) {
bool facing_west = direction == gamemap::location::NORTH_WEST || direction == gamemap::location::SOUTH_WEST;
bool facing_north = direction == gamemap::location::NORTH_WEST || direction == gamemap::location::NORTH || direction == gamemap::location::NORTH_EAST;
game_display::get_singleton()->render_unit_image(x- image->w/2, y - image->h/2, image, facing_west, false,
highlight_ratio(), blend_with_, blend_ratio(),0,!facing_north);
}
halo::remove(halo_id_);
halo_id_ = halo::NO_HALO;
if(!halo().empty()) {
halo::ORIENTATION orientation;
switch(direction)
{
case gamemap::location::NORTH:
case gamemap::location::NORTH_EAST:
orientation = halo::NORMAL;
break;
case gamemap::location::SOUTH_EAST:
case gamemap::location::SOUTH:
orientation = halo::VREVERSE;
break;
case gamemap::location::SOUTH_WEST:
orientation = halo::HVREVERSE;
break;
case gamemap::location::NORTH_WEST:
orientation = halo::HREVERSE;
break;
case gamemap::location::NDIRECTIONS:
default:
orientation = halo::NORMAL;
break;
}
if(direction != gamemap::location::SOUTH_WEST && direction != gamemap::location::NORTH_WEST) {
halo_id_ = halo::add(x+halo_x(),
y+halo_y(),
halo(),
gamemap::location(-1, -1),
orientation);
} else {
halo_id_ = halo::add(x-halo_x(),
y+halo_y(),
halo(),
gamemap::location(-1, -1),
orientation);
}
}
update_last_draw_time();
}
unit_animation::crude_animation::~crude_animation()
{
halo::remove(halo_id_);
halo_id_ = halo::NO_HALO;
}
void unit_animation::crude_animation::start_animation(int start_time,const gamemap::location &src,const gamemap::location &dst, bool cycles, double acceleration)
{
halo::remove(halo_id_);
halo_id_ = halo::NO_HALO;
animated<unit_frame>::start_animation(start_time,cycles,acceleration);
last_frame_begin_time_ = get_begin_time() -1;
if(src != gamemap::location::null_location || dst != gamemap::location::null_location) {
src_ = src;
dst_ = dst;
}
};

View file

@ -34,13 +34,33 @@ class unit_animation
public: public:
typedef enum { MATCH_FAIL=-2 , DEFAULT_ANIM=-1}; typedef enum { MATCH_FAIL=-2 , DEFAULT_ANIM=-1};
typedef enum { HIT, MISS, KILL, INVALID} hit_type; typedef enum { HIT, MISS, KILL, INVALID} hit_type;
static config prepare_animation(const config &cfg,const std::string animation_tag); static void initialize_anims( std::vector<unit_animation> & animations, const config & cfg, std::vector<attack_type> tmp_attacks);
unit_animation(){};
explicit unit_animation(const config& cfg,const std::string frame_string ="");
explicit unit_animation(int start_time,const unit_frame &frame,const std::string& even="",const int variation=0);
int matches(const game_display &disp,const gamemap::location& loc,const unit* my_unit,const std::string & event="",const int value=0,hit_type hit=INVALID,const attack_type* attack=NULL,const attack_type* second_attack = NULL, int swing_num =0) const; int matches(const game_display &disp,const gamemap::location& loc,const unit* my_unit,const std::string & event="",const int value=0,hit_type hit=INVALID,const attack_type* attack=NULL,const attack_type* second_attack = NULL, int swing_num =0) const;
const unit_frame& get_last_frame() const{ return unit_anim_.get_last_frame() ; };
void add_frame(int duration, const unit_frame& value,bool force_change =false){ unit_anim_.add_frame(duration,value,force_change) ; };
bool need_update() const;
bool animation_finished() const;
bool animation_would_finish() const;
void update_last_draw_time();
int get_begin_time() const;
int get_end_time() const;
int get_animation_time() const{ return unit_anim_.get_animation_time() ; };
void start_animation(int start_time,const gamemap::location &src = gamemap::location::null_location, const gamemap::location &dst = gamemap::location::null_location , bool cycles=false, double acceleration=1);
const int get_current_frame_begin_time() const{ return unit_anim_.get_current_frame_begin_time() ; };
void redraw();
// only to support all [attack_anim] format, to remove at 1.3.10 time
void back_compat_add_name(const std::string name="",const std::string range ="");
// to be privatized post 1.3.10
static config prepare_animation(const config &cfg,const std::string animation_tag);
explicit unit_animation(const config& cfg,const std::string frame_string ="");
friend class unit;
protected:
// reserved to class unit, for the special case of redrawing the unit base frame
image::locator image() const { return unit_anim_.get_current_frame().image() ; } image::locator image() const { return unit_anim_.get_current_frame().image() ; }
image::locator image_diagonal() const { return unit_anim_.get_current_frame().image_diagonal() ; } image::locator image_diagonal() const { return unit_anim_.get_current_frame().image_diagonal() ; }
std::string sound() const { return unit_anim_.get_current_frame().sound() ; }; std::string sound() const { return unit_anim_.get_current_frame().sound() ; };
@ -51,29 +71,15 @@ class unit_animation
double blend_ratio(const double default_val = 0) const{ return unit_anim_.blend_ratio(default_val); }; double blend_ratio(const double default_val = 0) const{ return unit_anim_.blend_ratio(default_val); };
fixed_t highlight_ratio(const float default_val = 1.0) const{ return unit_anim_.highlight_ratio(default_val); }; fixed_t highlight_ratio(const float default_val = 1.0) const{ return unit_anim_.highlight_ratio(default_val); };
double offset(double default_val =0.0) const{ return unit_anim_.offset(default_val); }; double offset(double default_val =0.0) const{ return unit_anim_.offset(default_val); };
bool need_update() const{return unit_anim_.need_update();};
bool animation_finished() const{ return unit_anim_.animation_finished() ; };
bool animation_would_finish() const{ return unit_anim_.animation_would_finish() ; };
const unit_frame& get_last_frame() const{ return unit_anim_.get_last_frame() ; };
void add_frame(int duration, const unit_frame& value,bool force_change =false){ unit_anim_.add_frame(duration,value,force_change) ; };
void start_animation(int start_time, bool cycles=false, double acceleration=1){ unit_anim_.start_animation(start_time, cycles, acceleration);};
int get_begin_time() const{ return unit_anim_.get_begin_time() ; };
void update_last_draw_time(){unit_anim_.update_last_draw_time();};
const int get_current_frame_begin_time() const{ return unit_anim_.get_current_frame_begin_time() ; };
int get_animation_time() const{ return unit_anim_.get_animation_time() ; };
int get_end_time() const{ return unit_anim_.get_end_time() ; };
// only to support all [attack_anim] format, to remove at 1.3.10 time
void back_compat_add_name(const std::string name="",const std::string range ="");
const animated<unit_frame> &get_missile_anim() const {return missile_anim_;}
static void back_compat_initialize_anims( std::vector<unit_animation> & animations, const config & cfg, std::vector<attack_type> tmp_attacks);
private: private:
unit_animation(){};
explicit unit_animation(int start_time,const unit_frame &frame,const std::string& even="",const int variation=0);
class crude_animation:public animated<unit_frame> class crude_animation:public animated<unit_frame>
{ {
public: public:
explicit crude_animation(int start_time=0):animated<unit_frame>(start_time){}; explicit crude_animation(int start_time=0):animated<unit_frame>(start_time){};
explicit crude_animation(const config& cfg,const std::string frame_string ="frame"); explicit crude_animation(const config& cfg,const std::string frame_string ="frame");
virtual ~crude_animation();
bool need_update() const; bool need_update() const;
const std::string &halo(const std::string&default_val ="") const; const std::string &halo(const std::string&default_val ="") const;
int halo_x(const int default_val = 0) const; int halo_x(const int default_val = 0) const;
@ -81,6 +87,8 @@ class unit_animation
double blend_ratio(const double default_val = 0) const; double blend_ratio(const double default_val = 0) const;
fixed_t highlight_ratio(const float default_val = 1.0) const; fixed_t highlight_ratio(const float default_val = 1.0) const;
double offset(double default_val =0.0) const; double offset(double default_val =0.0) const;
void redraw( );
void start_animation(int start_time,const gamemap::location& src,const gamemap::location& dst, bool cycles=false, double acceleration=1);
private: private:
//animation params that can be locally overridden by frames //animation params that can be locally overridden by frames
@ -91,6 +99,10 @@ class unit_animation
Uint32 blend_with_; Uint32 blend_with_;
progressive_double blend_ratio_; progressive_double blend_ratio_;
progressive_double highlight_ratio_; progressive_double highlight_ratio_;
gamemap::location src_;
gamemap::location dst_;
int halo_id_;
int last_frame_begin_time_;
}; };
t_translation::t_list terrain_types_; t_translation::t_list terrain_types_;
@ -105,7 +117,7 @@ class unit_animation
std::vector<config> secondary_attack_filter_; std::vector<config> secondary_attack_filter_;
std::vector<hit_type> hits_; std::vector<hit_type> hits_;
std::vector<int> swing_num_; std::vector<int> swing_num_;
crude_animation missile_anim_; std::map<std::string,crude_animation> sub_anims_;
crude_animation unit_anim_; crude_animation unit_anim_;
}; };

View file

@ -236,14 +236,8 @@ static void unit_attack_ranged(
disp->place_temporary_unit(defender,b); disp->place_temporary_unit(defender,b);
defender.set_hidden(false); defender.set_hidden(false);
const double acceleration = disp->turbo_speed();
// More damage shown for longer, but 1s at most for this factor
const double xsrc = disp->get_location_x(a);
const double ysrc = disp->get_location_y(a) - (attacker.is_flying() ? 0 : disp->get_map().get_terrain_info(disp->get_map().get_terrain(a)).unit_height_adjust());
const double xdst = disp->get_location_x(b);
const double ydst = disp->get_location_y(b) -( defender.is_flying() ? 0 : disp->get_map().get_terrain_info(disp->get_map().get_terrain(b)).unit_height_adjust());
gamemap::location update_tiles[6]; gamemap::location update_tiles[6];
get_adjacent_tiles(b,update_tiles); get_adjacent_tiles(b,update_tiles);
@ -253,7 +247,6 @@ static void unit_attack_ranged(
// Start leader and attacker animation, wait for attacker animation to end // Start leader and attacker animation, wait for attacker animation to end
attacker.set_attacking(*disp,a,damage,attack,secondary_attack,swing); attacker.set_attacking(*disp,a,damage,attack,secondary_attack,swing);
animated<unit_frame> missile_animation = attacker.get_animation()->get_missile_anim();
const gamemap::location leader_loc = under_leadership(units,a); const gamemap::location leader_loc = under_leadership(units,a);
unit_map::iterator leader = units.end(); unit_map::iterator leader = units.end();
if(leader_loc.valid()){ if(leader_loc.valid()){
@ -289,15 +282,12 @@ static void unit_attack_ranged(
orientation = halo::NORMAL; orientation = halo::NORMAL;
break; break;
} }
const bool vertical_dir = (a.x == b.x) ? true:false;
defender.set_defending(*disp,b,damage,&attack,secondary_attack,swing); defender.set_defending(*disp,b,damage,&attack,secondary_attack,swing);
// Min of attacker, defender, missile and -200 // Min of attacker, defender, missile and -200
int start_time = -200; int start_time = -200;
start_time = minimum<int>(start_time,defender.get_animation()->get_begin_time()); start_time = minimum<int>(start_time,defender.get_animation()->get_begin_time());
start_time = minimum<int>(start_time,missile_animation.get_begin_time());
start_time = minimum<int>(start_time,attacker.get_animation()->get_begin_time()); start_time = minimum<int>(start_time,attacker.get_animation()->get_begin_time());
missile_animation.start_animation(start_time,false,acceleration);
defender.restart_animation(*disp,start_time); defender.restart_animation(*disp,start_time);
attacker.restart_animation(*disp,start_time); attacker.restart_animation(*disp,start_time);
animation_time = defender.get_animation()->get_animation_time(); animation_time = defender.get_animation()->get_animation_time();
@ -307,56 +297,9 @@ static void unit_attack_ranged(
while(!hide && ( while(!hide && (
!attacker.get_animation()->animation_would_finish() || !attacker.get_animation()->animation_would_finish() ||
!defender.get_animation()->animation_would_finish() || !defender.get_animation()->animation_would_finish() ||
!missile_animation.animation_finished() ||
(leader_loc.valid() && !leader->second.get_animation()->animation_finished()) || (leader_loc.valid() && !leader->second.get_animation()->animation_finished()) ||
damage >0) damage >0)
){ ){
const unit_frame& missile_frame = missile_animation.get_current_frame();
double pos = missile_frame.offset(missile_animation.get_current_frame_time(),
double(animation_time -missile_animation.get_begin_time())/
double(missile_animation.get_end_time()-missile_animation.get_begin_time()));
disp->invalidate(b);
disp->invalidate(a);
if(leader_loc.valid()) disp->invalidate(leader_loc);
halo::remove(missile_halo);
halo::remove(missile_frame_halo);
missile_halo = halo::NO_HALO;
missile_frame_halo = halo::NO_HALO;
if(animation_time > missile_animation.get_begin_time() &&
animation_time < missile_animation.get_end_time() &&
(!disp->fogged(b) || !disp->fogged(a))) {
const int posx = int(pos*xdst + (1.0-pos)*xsrc);
const int posy = int(pos*ydst + (1.0-pos)*ysrc);
image::locator missile_image= missile_frame.image();
const int d = disp->hex_size() / 2;
if(vertical_dir) {
missile_image = missile_frame.image();
} else {
missile_image = missile_frame.image_diagonal();
}
if(!missile_frame.halo(missile_animation.get_current_frame_time()).empty()) {
if(attack_ori != gamemap::location::SOUTH_WEST && attack_ori != gamemap::location::NORTH_WEST) {
missile_halo = halo::add(posx+d+missile_frame.halo_x(missile_animation.get_current_frame_time()),
posy+d+missile_frame.halo_y(missile_animation.get_current_frame_time()),
missile_frame.halo(missile_animation.get_current_frame_time()),
gamemap::location(-1, -1),
orientation);
} else {
missile_halo = halo::add(posx+d-missile_frame.halo_x(missile_animation.get_current_frame_time()),
posy+d+missile_frame.halo_y(missile_animation.get_current_frame_time()),
missile_frame.halo(missile_animation.get_current_frame_time()),
gamemap::location(-1, -1),
orientation);
}
}
missile_frame_halo = halo::add(posx+d,
posy+d,
missile_image.get_filename(),
gamemap::location(-1, -1),
orientation);
}
if(!sound_played && animation_time > 0) { if(!sound_played && animation_time > 0) {
sound_played = true; sound_played = true;
std::string text ; std::string text ;
@ -376,11 +319,10 @@ static void unit_attack_ranged(
} }
disp->draw(); disp->draw();
events::pump(); events::pump();
missile_animation.update_last_draw_time();
disp->delay(10); disp->delay(10);
// We use missile animation because it's the only one // We use missile animation because it's the only one
// not reseted in the middle to go to standing // not reseted in the middle to go to standing
animation_time = missile_animation.get_animation_time(); animation_time = attacker.get_animation()->get_animation_time();
} }
halo::remove(missile_halo); halo::remove(missile_halo);

View file

@ -44,6 +44,7 @@ attack_type::attack_type(const config& cfg,const std::string& id, bool with_anim
} }
if (with_animations) { if (with_animations) {
const config expanded_cfg = unit_animation::prepare_animation(cfg,"animation"); const config expanded_cfg = unit_animation::prepare_animation(cfg,"animation");
// TODO: prepare animation should be privatized once the code is removed
const config::child_list& animations = expanded_cfg.get_children("animation"); const config::child_list& animations = expanded_cfg.get_children("animation");
for(config::child_list::const_iterator d = animations.begin(); d != animations.end(); ++d) { for(config::child_list::const_iterator d = animations.begin(); d != animations.end(); ++d) {
lg::wml_error<<"attack animation directly in attack is deprecated, support will be removed in 1.3.10 (in unit "<<id<<")\n"; lg::wml_error<<"attack animation directly in attack is deprecated, support will be removed in 1.3.10 (in unit "<<id<<")\n";
@ -627,13 +628,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
experience_needed_=lexical_cast_default<int>(cfg_["experience"],500); experience_needed_=lexical_cast_default<int>(cfg_["experience"],500);
config expanded_cfg = unit_animation::prepare_animation(cfg,"animation"); unit_animation::initialize_anims(animations_,cfg,attacks(true));
const config::child_list& animations = expanded_cfg.get_children("animation");
config::child_list::const_iterator anim_itor;
for(anim_itor = animations.begin(); anim_itor != animations.end(); ++anim_itor) {
animations_.push_back(unit_animation(**anim_itor));
}
unit_animation::back_compat_initialize_anims(animations_,cfg,attacks(true));
flag_rgb_ = cfg["flag_rgb"]; flag_rgb_ = cfg["flag_rgb"];
game_config::add_color_info(cfg); game_config::add_color_info(cfg);
// Deprecation messages, only seen when unit is parsed for the first time. // Deprecation messages, only seen when unit is parsed for the first time.