move attack animations out of [attack] and into [unit], code+wmllint

This commit is contained in:
Jérémy Rosen 2007-09-08 07:51:22 +00:00
parent 093439695c
commit d84b7f63b3
10 changed files with 226 additions and 201 deletions

14
RELEASE_NOTES Normal file
View file

@ -0,0 +1,14 @@
This file is here to allow devs to easily add stuff in the release notes for the next release,
it allows easy syncing with the release team, since you don't have to be around when the release takes place...
just dump whatever you want to have mentionned in the release notes here.
The release team can empty this file after each Release..
Boucman:
The old [animation] in [attack] that was used to describe attack animations has been deprecated...
you can now use an [attack_anim] block within the [unit] block...
this means that attack animations work in a similar fashion to all other anims, and should be easier to edit/add via WML

View file

@ -47,6 +47,8 @@
* a minus sign in front of a cardinal direction now reverses it ("-s"="n") * a minus sign in front of a cardinal direction now reverses it ("-s"="n")
* now radius expansion is handled last in Standard Location Filters; * now radius expansion is handled last in Standard Location Filters;
previously it was handled last except before [and], [or], and [not] previously it was handled last except before [and], [or], and [not]
* the WML for attack animations has been moved from the [attack] block to
the [unit] block...
* fix a bug with array.length side-effects causing empty arrays to increase * fix a bug with array.length side-effects causing empty arrays to increase
to size 1 to size 1
* miscellaneous and bug fixes: * miscellaneous and bug fixes:

View file

@ -541,7 +541,6 @@ def hack_syntax(filename, lines):
modcount += 1 modcount += 1
need_image = False need_image = False
# Boucman's transformation of animation syntax # Boucman's transformation of animation syntax
if future:
class anim_frame: class anim_frame:
def __init__(self, attackline, attackname, lineno, female): def __init__(self, attackline, attackname, lineno, female):
self.attackstart = attackline self.attackstart = attackline

View file

@ -1310,6 +1310,7 @@ void unit::read(const config& cfg, bool use_traits)
const config::child_list& leading_anims = cfg_.get_children("leading_anim"); const config::child_list& leading_anims = cfg_.get_children("leading_anim");
const config::child_list& defends = cfg_.get_children("defend"); const config::child_list& defends = cfg_.get_children("defend");
const config::child_list& attack_anim = cfg_.get_children("attack_anim");
const config::child_list& teleports = cfg_.get_children("teleport_anim"); const config::child_list& teleports = cfg_.get_children("teleport_anim");
const config::child_list& extra_anims = cfg_.get_children("extra_anim"); const config::child_list& extra_anims = cfg_.get_children("extra_anim");
const config::child_list& deaths = cfg_.get_children("death"); const config::child_list& deaths = cfg_.get_children("death");
@ -1408,6 +1409,22 @@ void unit::read(const config& cfg, bool use_traits)
} }
animations_.push_back(unit_animation(0,unit_frame(absolute_image(),150),"movement",unit_animation::DEFAULT_ANIM)); animations_.push_back(unit_animation(0,unit_frame(absolute_image(),150),"movement",unit_animation::DEFAULT_ANIM));
// Always have a movement animation // Always have a movement animation
bool found_attack = false;
for(config::child_list::const_iterator d = attack_anim.begin(); d != attack_anim.end(); ++d) {
animations_.push_back(unit_animation(**d));
found_attack = true;
//lg::wml_error<<"attack animations are deprecate, support will be removed in 1.3.8 (in unit "<<id_<<")\n";
//lg::wml_error<<"please put it with an [animation] tag and apply_to=attack flag\n";
}
// TODO backward compat code, to be removed in 1.3.10, support for old attack format ([animation] in [attack] )
if(found_attack == false) {
std::vector<attack_type> tmp_attacks = type()->attacks();
for(std::vector<attack_type>::iterator attacks_itor = tmp_attacks.begin() ; attacks_itor!= tmp_attacks.end();attacks_itor++) {
animations_.insert(animations_.end(),attacks_itor->animation_.begin(),attacks_itor->animation_.end());
}
}
animations_.push_back(unit_animation(-150,unit_frame(absolute_image(),300),"attack",unit_animation::DEFAULT_ANIM));
// always have an attack animation
for(config::child_list::const_iterator d2 = defends.begin(); d2 != defends.end(); ++d2) { for(config::child_list::const_iterator d2 = defends.begin(); d2 != defends.end(); ++d2) {
(**d2)["apply_to"]="defend"; (**d2)["apply_to"]="defend";
(**d2)["value"]=(**d2)["damage"]; (**d2)["value"]=(**d2)["damage"];
@ -1652,7 +1669,7 @@ void unit::set_extra_anim(const game_display &disp,const gamemap::location& loc,
} }
const unit_animation & unit::set_attacking(const game_display &disp,const gamemap::location& loc,int damage,const attack_type& type,const attack_type* secondary_attack,int swing_num) void unit::set_attacking(const game_display &disp,const gamemap::location& loc,int damage,const attack_type& type,const attack_type* secondary_attack,int swing_num)
{ {
state_ = STATE_ATTACKING; state_ = STATE_ATTACKING;
unit_animation::hit_type hit_type; unit_animation::hit_type hit_type;
@ -1663,7 +1680,7 @@ const unit_animation & unit::set_attacking(const game_display &disp,const gamema
}else { }else {
hit_type = unit_animation::MISS; hit_type = unit_animation::MISS;
} }
return *start_animation(disp,loc,type.animation(disp,loc,this,hit_type,secondary_attack,swing_num,damage),true,true); start_animation(disp,loc,choose_animation(disp,loc,"attack",damage,hit_type,&type,secondary_attack,swing_num),true);
} }
void unit::set_leading(const game_display &disp,const gamemap::location& loc) void unit::set_leading(const game_display &disp,const gamemap::location& loc)
@ -1737,22 +1754,16 @@ void unit::set_idling(const game_display &disp,const gamemap::location& loc)
start_animation(disp,loc,choose_animation(disp,loc,"idling"),true); start_animation(disp,loc,choose_animation(disp,loc,"idling"),true);
} }
const unit_animation* unit::start_animation(const game_display &disp, const gamemap::location &loc,const unit_animation * animation,bool with_bars,bool is_attack_anim) void unit::start_animation(const game_display &disp, const gamemap::location &loc,const unit_animation * animation,bool with_bars)
{ {
if(!animation) { if(!animation) {
set_standing(disp,loc,with_bars); set_standing(disp,loc,with_bars);
return NULL; return ;
} }
draw_bars_ = with_bars; draw_bars_ = with_bars;
offset_=0; offset_=0;
if(anim_) delete anim_; if(anim_) delete anim_;
if(!is_attack_anim) {
anim_ = new unit_animation(*animation); anim_ = new unit_animation(*animation);
} else {
//! @todo TODO this, the is_attack_anim param and the return value are ugly hacks
// that need to be taken care of eventually
anim_ = new attack_animation(*(static_cast<const attack_animation*>(animation)));
}
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed()); anim_->start_animation(anim_->get_begin_time(), false, 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()) {
@ -1761,11 +1772,6 @@ const unit_animation* unit::start_animation(const game_display &disp, const game
} else { } else {
next_idling_ = INT_MAX; next_idling_ = INT_MAX;
} }
if(is_attack_anim) {
return &(static_cast<attack_animation*>(anim_))->get_missile_anim();
} else {
return NULL;
}
} }
void unit::restart_animation(const game_display& disp,int start_time) { void unit::restart_animation(const game_display& disp,int start_time) {

View file

@ -184,7 +184,7 @@ public:
void set_extra_anim(const game_display& disp,const gamemap::location& loc, std::string flag); void set_extra_anim(const game_display& disp,const gamemap::location& loc, std::string flag);
void set_dying(const game_display &disp,const gamemap::location& loc,const attack_type* attack,const attack_type* secondary_attack); void set_dying(const game_display &disp,const gamemap::location& loc,const attack_type* attack,const attack_type* secondary_attack);
void set_walking(const game_display& disp,const gamemap::location& loc); void set_walking(const game_display& disp,const gamemap::location& loc);
const unit_animation & set_attacking( const game_display &disp,const gamemap::location& loc,int damage,const attack_type& type,const attack_type* secondary_attack,int swing_num); void set_attacking( const game_display &disp,const gamemap::location& loc,int damage,const attack_type& type,const attack_type* secondary_attack,int swing_num);
void set_recruited(const game_display& disp,const gamemap::location& loc); void set_recruited(const game_display& disp,const gamemap::location& loc);
void set_healed(const game_display& disp,const gamemap::location& loc,int healing); void set_healed(const game_display& disp,const gamemap::location& loc,int healing);
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);
@ -249,7 +249,7 @@ public:
STATE_DYING, STATE_EXTRA, STATE_TELEPORT, STATE_DYING, STATE_EXTRA, STATE_TELEPORT,
STATE_RECRUITED, STATE_HEALED, STATE_POISONED, STATE_RECRUITED, STATE_HEALED, STATE_POISONED,
STATE_IDLEIN, STATE_IDLING, STATE_VICTORIOUS}; STATE_IDLEIN, STATE_IDLING, STATE_VICTORIOUS};
const unit_animation * start_animation(const game_display &disp, const gamemap::location &loc,const unit_animation* animation, bool with_bars,bool is_attack_anim =false); void start_animation(const game_display &disp, const gamemap::location &loc,const unit_animation* animation, bool with_bars);
//! The name of the file to game_display (used in menus). //! The name of the file to game_display (used in menus).
const std::string& absolute_image() const { return cfg_["image"]; } const std::string& absolute_image() const { return cfg_["image"]; }
@ -266,7 +266,6 @@ public:
const unit_animation* choose_animation(const game_display& disp, const gamemap::location& loc,const std::string& event,const int damage=0,const unit_animation::hit_type hit_type = unit_animation::INVALID,const attack_type* attack=NULL,const attack_type* second_attack = NULL, int swing_num =0) const; const unit_animation* choose_animation(const game_display& disp, const gamemap::location& loc,const std::string& event,const int damage=0,const unit_animation::hit_type hit_type = unit_animation::INVALID,const attack_type* attack=NULL,const attack_type* second_attack = NULL, int swing_num =0) const;
bool get_ability_bool(const std::string& ability, const gamemap::location& loc) const; bool get_ability_bool(const std::string& ability, const gamemap::location& loc) const;
unit_ability_list get_abilities(const std::string& ability, const gamemap::location& loc) const; unit_ability_list get_abilities(const std::string& ability, const gamemap::location& loc) const;
std::vector<std::string> ability_tooltips(const gamemap::location& loc) const; std::vector<std::string> ability_tooltips(const gamemap::location& loc) const;

View file

@ -163,6 +163,13 @@ unit_animation::unit_animation(const config& cfg,const std::string frame_string
for(itor = cfg.child_range("secondary_attack_filter").first; itor <cfg.child_range("secondary_attack_filter").second;itor++) { for(itor = cfg.child_range("secondary_attack_filter").first; itor <cfg.child_range("secondary_attack_filter").second;itor++) {
secondary_attack_filter_.push_back(**itor); secondary_attack_filter_.push_back(**itor);
} }
// this whole block is a temporary hack that will stay until proper multi-frame in anim is supported...
range = cfg.child_range("missile_frame");
for(; range.first != range.second; ++range.first) {
unit_frame tmp_frame(**range.first);
missile_anim_.add_frame(tmp_frame.duration(),tmp_frame,!tmp_frame.does_not_change());
}
} }
int unit_animation::matches(const game_display &disp,const gamemap::location& loc, const unit* my_unit,const std::string & event,const int value,hit_type hit,const attack_type* attack,const attack_type* second_attack, int swing_num) const int unit_animation::matches(const game_display &disp,const gamemap::location& loc, const unit* my_unit,const std::string & event,const int value,hit_type hit,const attack_type* attack,const attack_type* second_attack, int swing_num) const
@ -259,3 +266,11 @@ int unit_animation::matches(const game_display &disp,const gamemap::location& lo
} }
void unit_animation::back_compat_add_name(const std::string name)
{
config tmp;
tmp["name"] = name;
event_.push_back("attack");
primary_attack_filter_.push_back(tmp);
}

View file

@ -41,6 +41,9 @@ class unit_animation:public animated<unit_frame>
explicit unit_animation(int start_time,const unit_frame &frame,const std::string& even="",const int variation=0); 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;
// only to support all [attack_anim] format, to remove at 1.3.10 time
void back_compat_add_name(const std::string name);
const animated<unit_frame> &get_missile_anim() const {return missile_anim_;}
private: private:
t_translation::t_list terrain_types_; t_translation::t_list terrain_types_;
std::vector<config> unit_filter_; std::vector<config> unit_filter_;
@ -54,20 +57,8 @@ class unit_animation:public animated<unit_frame>
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_;
animated<unit_frame> missile_anim_;
}; };
class attack_animation: public unit_animation
{
public:
explicit attack_animation(const config& cfg):unit_animation(cfg),missile_anim(cfg,"missile_frame"){};
explicit attack_animation(int start_time,const unit_frame &frame):unit_animation(start_time,frame) {};
const unit_animation &get_missile_anim() {return missile_anim;}
private:
unit_animation missile_anim;
};
#endif #endif

View file

@ -252,7 +252,8 @@ 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
unit_animation missile_animation = 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()){

View file

@ -65,20 +65,20 @@ attack_type::attack_type(const config& cfg,const std::string& id, const std::str
const config expanded_cfg = unit_animation::prepare_animation(cfg,"animation"); const config expanded_cfg = unit_animation::prepare_animation(cfg,"animation");
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) {
animation_.push_back(attack_animation(**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<<"please put it with an [attack_anim] tag in the [unit] and filter on the attack name\n";
animation_.push_back(unit_animation(**d));
animation_.back().back_compat_add_name(cfg["name"]);
} }
if(cfg.child("frame") || cfg.child("missile_frame") || cfg.child("sound")) { if(cfg.child("frame") || cfg.child("missile_frame") || cfg.child("sound")) {
LOG_STREAM(err, config) << "the animation for " << cfg["name"] << "in unit " << id lg::wml_error<<"using frame directly in attack is VERY deprecated, support will be removed in 1.3.10 (in unit "<<id<<")\n";
<< " is directly in the attack, please use [animation]\n" ;
} }
if(animation_.empty()) { if(animation_.empty()) {
animation_.push_back(attack_animation(cfg)); animation_.push_back(unit_animation(cfg));
animation_.back().back_compat_add_name(cfg["name"]);
} }
if(animation_.empty()) { animation_.push_back(unit_animation(-200,unit_frame(image_fighting,300),"attack",unit_animation::DEFAULT_ANIM));
animation_.push_back(attack_animation(-200,unit_frame(image_fighting,300))); animation_.back().back_compat_add_name(cfg["name"]);
}
assert(!animation_.empty());
} }
id_ = unit_id_test(cfg["name"]); id_ = unit_id_test(cfg["name"]);
@ -111,26 +111,6 @@ attack_type::attack_type(const config& cfg,const std::string& id, const std::str
} }
const attack_animation* attack_type::animation(const game_display& disp, const gamemap::location& loc,const unit* my_unit,
const unit_animation::hit_type hit,const attack_type*secondary_attack,int swing_num,int damage) const
{
// Select one of the matching animations at random
std::vector<const attack_animation*> options;
int max_val = -3;
for(std::vector<attack_animation>::const_iterator i = animation_.begin(); i != animation_.end(); ++i) {
int matching = i->matches(disp,loc,my_unit,"attack",damage,hit,this,secondary_attack,swing_num);
if(matching == max_val) {
options.push_back(&*i);
} else if(matching > max_val) {
max_val = matching;
options.erase(options.begin(),options.end());
options.push_back(&*i);
}
}
if(options.empty()) return NULL;
return options[rand()%options.size()];
}
bool attack_type::matches_filter(const config& cfg,bool self) const bool attack_type::matches_filter(const config& cfg,bool self) const
{ {
@ -785,6 +765,22 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
} }
animations_.push_back(unit_animation(-150,unit_frame(image(),300),"defend",unit_animation::DEFAULT_ANIM)); animations_.push_back(unit_animation(-150,unit_frame(image(),300),"defend",unit_animation::DEFAULT_ANIM));
// Always have a defensive animation // Always have a defensive animation
expanded_cfg = unit_animation::prepare_animation(cfg,"attack_anim");
const config::child_list& attack_anims = expanded_cfg.get_children("attack_anim");
for(config::child_list::const_iterator d = attack_anims.begin(); d != attack_anims.end(); ++d) {
(**d)["apply_to"] ="attack";
animations_.push_back(unit_animation(**d));
//lg::wml_error<<"attack animations are deprecate, support will be removed in 1.3.8 (in unit "<<id()<<")\n";
//lg::wml_error<<"please put it with an [animation] tag and apply_to=attack flag\n";
}
// get old animation format, to be removed circum 1.3.10
std::vector<attack_type> tmp_attacks = attacks(true);
for(std::vector<attack_type>::iterator attacks_itor = tmp_attacks.begin() ; attacks_itor!= tmp_attacks.end();attacks_itor++) {
animations_.insert(animations_.end(),attacks_itor->animation_.begin(),attacks_itor->animation_.end());
// this has been detected elsewhere, no deprecation message needed here
}
animations_.push_back(unit_animation(-150,unit_frame(image(),300),"attack",unit_animation::DEFAULT_ANIM));
// always have an attack animation
expanded_cfg = unit_animation::prepare_animation(cfg,"death"); expanded_cfg = unit_animation::prepare_animation(cfg,"death");
const config::child_list& deaths = expanded_cfg.get_children("death"); const config::child_list& deaths = expanded_cfg.get_children("death");
for(anim_itor = deaths.begin(); anim_itor != deaths.end(); ++anim_itor) { for(anim_itor = deaths.begin(); anim_itor != deaths.end(); ++anim_itor) {

View file

@ -90,9 +90,11 @@ public:
bool special_affects_self(const config& cfg) const; bool special_affects_self(const config& cfg) const;
config cfg_; config cfg_;
const attack_animation* animation(const game_display& disp, const gamemap::location& loc,const unit* my_unit,const unit_animation::hit_type hit,const attack_type* secondary_attack,int swing_num,int damage) const; const unit_animation* animation(const game_display& disp, const gamemap::location& loc,const unit* my_unit,const unit_animation::hit_type hit,const attack_type* secondary_attack,int swing_num,int damage) const;
// made public to ease backward compatibility for WML syntax
// to be removed (with all corresponding code once 1.3.6 is reached
std::vector<unit_animation> animation_;
private: private:
std::vector<attack_animation> animation_;
t_string description_; t_string description_;
std::string id_; std::string id_;
std::string type_; std::string type_;