new animation type: recruiting (c++ part only)

This commit is contained in:
Jérémy Rosen 2009-03-29 10:26:47 +00:00
parent 6c7d19f0b4
commit be7769eda1
8 changed files with 65 additions and 38 deletions

View file

@ -13,6 +13,8 @@ Version 1.7.0-svn:
* The ~RC() image functor does not accept the special palette switch
~RC(palette1=palette2) syntax anymore. ~PAL(palette1>palette2) should
be used instead
* New type of animation : "recruiting" used by leaders when recruiting
units
* New portrait for Orc Grunt, Dwarf Fighter (alternative), Goblin Spearman
Ogre/Young Ogre, Trapper
* Language and i18n:

View file

@ -191,7 +191,7 @@ std::string recruit_unit(const gamemap& map, const int side, unit_map& units,
}
const unit_map::iterator new_unit_itor = units.find(recruit_location);
if(new_unit_itor != units.end()) new_unit_itor->second.set_hidden(false);
if(show)unit_display::unit_recruited(recruit_location);
if(show)unit_display::unit_recruited(recruit_location,u->first);
if (is_recall)
{
LOG_NG << "firing recall event\n";
@ -1179,9 +1179,9 @@ attack::attack(game_display& gui, const gamemap& map,
refresh_bc();
if(!a_.valid()) {
unit_display::unit_die(d_.iter_->first, d_.get_unit(), NULL, d_stats_->weapon, NULL);
unit_display::unit_die(d_.iter_->first, d_.get_unit(), NULL, d_stats_->weapon);
} else {
unit_display::unit_die(d_.iter_->first, d_.get_unit(),a_stats_->weapon,d_stats_->weapon, &(a_.get_unit()));
unit_display::unit_die(d_.iter_->first, d_.get_unit(),a_stats_->weapon,d_stats_->weapon,a_.iter_->first, &(a_.get_unit()));
}
DELAY_END_LEVEL(delayed_exception, game_events::fire("die",death_loc,attacker_loc, dat));
@ -1449,9 +1449,9 @@ attack::attack(game_display& gui, const gamemap& map,
refresh_bc();
if(!d_.valid()) {
unit_display::unit_die(a_.loc_, a_.get_unit(),a_stats_->weapon, NULL, NULL);
unit_display::unit_die(a_.loc_, a_.get_unit(),a_stats_->weapon);
} else {
unit_display::unit_die(a_.loc_, a_.get_unit(),a_stats_->weapon,d_stats_->weapon, &(d_.get_unit()));
unit_display::unit_die(a_.loc_, a_.get_unit(),a_stats_->weapon,d_stats_->weapon,d_.loc_, &(d_.get_unit()));
}
DELAY_END_LEVEL(delayed_exception, game_events::fire("die",death_loc,defender_loc,dat));

View file

@ -2827,13 +2827,15 @@ const t_string& unit::modification_description(const std::string& type) const
const unit_animation* unit::choose_animation(const game_display& disp, const map_location& loc,const std::string& event,const int value,const unit_animation::hit_type hit,const attack_type* attack,const attack_type* second_attack, int swing_num) const
const unit_animation* unit::choose_animation(const game_display& disp, const map_location& loc,const std::string& event,
const map_location& second_loc,const int value,const unit_animation::hit_type hit,
const attack_type* attack, const attack_type* second_attack, int swing_num) const
{
// Select one of the matching animations at random
std::vector<const unit_animation*> options;
int max_val = unit_animation::MATCH_FAIL;
for(std::vector<unit_animation>::const_iterator i = animations_.begin(); i != animations_.end(); ++i) {
int matching = i->matches(disp,loc,this,event,value,hit,attack,second_attack,swing_num);
int matching = i->matches(disp,loc,second_loc,this,event,value,hit,attack,second_attack,swing_num);
if(matching > unit_animation::MATCH_FAIL && matching == max_val) {
options.push_back(&*i);
} else if(matching > max_val) {

View file

@ -278,7 +278,13 @@ public:
unit_type::ALIGNMENT alignment() const { return alignment_; }
const unit_race* race() const { return race_; }
const unit_animation* choose_animation(const game_display& disp, const map_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 map_location& loc, const std::string& event,
const map_location& second_loc = map_location::null_location,
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 map_location& loc) const;
unit_ability_list get_abilities(const std::string& ability, const map_location& loc) const;

View file

@ -201,7 +201,7 @@ unit_animation::unit_animation(const config& cfg,const std::string frame_string
}
int unit_animation::matches(const game_display &disp,const map_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 map_location& loc,const map_location& second_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 result = base_score_;
if(!event.empty()&&!event_.empty()) {
@ -240,13 +240,12 @@ int unit_animation::matches(const game_display &disp,const map_location& loc, co
result++;
}
if(!secondary_unit_filter_.empty()) {
const map_location facing_loc = loc.get_direction(my_unit->facing());
unit_map::const_iterator unit;
for(unit=disp.get_const_units().begin() ; unit != disp.get_const_units().end() ; unit++) {
if(unit->first == facing_loc) {
if(unit->first == second_loc) {
std::vector<config>::const_iterator second_itor;
for(second_itor = secondary_unit_filter_.begin(); second_itor != secondary_unit_filter_.end(); second_itor++) {
if(!unit->second.matches_filter(&(*second_itor),facing_loc)) return MATCH_FAIL;
if(!unit->second.matches_filter(&(*second_itor),second_loc)) return MATCH_FAIL;
result++;
}
@ -854,7 +853,8 @@ void unit_animation::particule::start_animation(int start_time, bool cycles)
}
void unit_animator::add_animation(unit* animated_unit,const std::string& event,
const map_location &src , const int value,bool with_bars,bool cycles,
const map_location &src , const map_location &dst ,
const int value,bool with_bars,bool cycles,
const std::string text,const Uint32 text_color,
const unit_animation::hit_type hit_type,
const attack_type* attack, const attack_type* second_attack, int swing_num)
@ -868,7 +868,7 @@ void unit_animator::add_animation(unit* animated_unit,const std::string& event,
tmp.src = src;
tmp.with_bars= with_bars;
tmp.cycles = cycles;
tmp.animation = animated_unit->choose_animation(*disp,src,event,value,hit_type,attack,second_attack,swing_num);
tmp.animation = animated_unit->choose_animation(*disp,src,event,dst,value,hit_type,attack,second_attack,swing_num);
if(!tmp.animation) return;
@ -877,7 +877,8 @@ void unit_animator::add_animation(unit* animated_unit,const std::string& event,
animated_units_.push_back(tmp);
}
void unit_animator::replace_anim_if_invalid(unit* animated_unit,const std::string& event,
const map_location &src , const int value,bool with_bars,bool cycles,
const map_location &src , const map_location & dst,
const int value,bool with_bars,bool cycles,
const std::string text,const Uint32 text_color,
const unit_animation::hit_type hit_type,
const attack_type* attack, const attack_type* second_attack, int swing_num)
@ -886,7 +887,7 @@ void unit_animator::replace_anim_if_invalid(unit* animated_unit,const std::strin
game_display*disp = game_display::get_singleton();
if(animated_unit->get_animation() &&
!animated_unit->get_animation()->animation_finished_potential() &&
animated_unit->get_animation()->matches(*disp,src,animated_unit,event,value,hit_type,attack,second_attack,swing_num) >unit_animation::MATCH_FAIL) {
animated_unit->get_animation()->matches(*disp,src,dst,animated_unit,event,value,hit_type,attack,second_attack,swing_num) >unit_animation::MATCH_FAIL) {
anim_elem tmp;
tmp.my_unit = animated_unit;
tmp.text = text;
@ -897,7 +898,7 @@ void unit_animator::replace_anim_if_invalid(unit* animated_unit,const std::strin
tmp.animation = NULL;
animated_units_.push_back(tmp);
}else {
add_animation(animated_unit,event,src,value,with_bars,cycles,text,text_color,hit_type,attack,second_attack,swing_num);
add_animation(animated_unit,event,src,dst,value,with_bars,cycles,text,text_color,hit_type,attack,second_attack,swing_num);
}
}
void unit_animator::start_animations()

View file

@ -38,7 +38,7 @@ class unit_animation
static void fill_initial_animations( std::vector<unit_animation> & animations, const config & cfg);
static void add_anims( std::vector<unit_animation> & animations, const config & cfg);
int matches(const game_display &disp,const map_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 map_location& loc,const map_location& second_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() ; };
@ -130,6 +130,7 @@ class unit_animator
void add_animation(unit* animated_unit,const std::string& event,
const map_location &src = map_location::null_location,
const map_location &dst = map_location::null_location,
const int value=0,bool with_bars = false,bool cycles = false,
const std::string text="",const Uint32 text_color=0,
const unit_animation::hit_type hit_type = unit_animation::INVALID,
@ -137,6 +138,7 @@ class unit_animator
int swing_num =0);
void replace_anim_if_invalid(unit* animated_unit,const std::string& event,
const map_location &src = map_location::null_location,
const map_location &dst = map_location::null_location,
const int value=0,bool with_bars = false,bool cycles = false,
const std::string text="",const Uint32 text_color=0,
const unit_animation::hit_type hit_type = unit_animation::INVALID,

View file

@ -67,7 +67,7 @@ static void move_unit_between(const map_location& a, const map_location& b, unit
disp->place_temporary_unit(temp_unit,a);
temp_unit.set_facing(a.get_relative_dir(b));
unit_animator animator;
animator.replace_anim_if_invalid(&temp_unit,"movement",a);
animator.replace_anim_if_invalid(&temp_unit,"movement",a,b);
animator.start_animations();
animator.pause_animation();
disp->scroll_to_tiles(a,b,game_display::ONSCREEN,true,0.0,false);
@ -207,7 +207,7 @@ void move_unit(const std::vector<map_location>& path, unit& u, const std::vector
}
void unit_die(const map_location& loc, unit& loser,
const attack_type* attack,const attack_type* secondary_attack, unit* winner)
const attack_type* attack,const attack_type* secondary_attack, const map_location& winner_loc,unit* winner)
{
game_display* disp = game_display::get_singleton();
if(!disp ||disp->video().update_locked() || disp->fogged(loc) || preferences::show_combat() == false) {
@ -215,9 +215,9 @@ void unit_die(const map_location& loc, unit& loser,
}
unit_animator animator;
// hide the hp/xp bars of the loser (useless and prevent bars around an erased unit)
animator.add_animation(&loser,"death",loc,0,false,false,"",0,unit_animation::KILL,attack,secondary_attack,0);
animator.add_animation(&loser,"death",loc,winner_loc,0,false,false,"",0,unit_animation::KILL,attack,secondary_attack,0);
// but show the bars of the winner (avoid blinking and show its xp gain)
animator.add_animation(winner,"victory",loc.get_direction(loser.facing()),0,true,false,"",0,
animator.add_animation(winner,"victory",winner_loc,loc,0,true,false,"",0,
unit_animation::KILL,secondary_attack,attack,0);
animator.start_animations();
animator.wait_for_end();
@ -292,8 +292,8 @@ void unit_attack(
}else {
hit_type = unit_animation::MISS;
}
animator.add_animation(&attacker,"attack",att->first,damage,true,false,text_2,display::rgb(0,255,0),hit_type,&attack,secondary_attack,swing);
animator.add_animation(&defender,"defend",def->first,damage,true,false,text ,display::rgb(255,0,0),hit_type,&attack,secondary_attack,swing);
animator.add_animation(&attacker,"attack",att->first,def->first,damage,true,false,text_2,display::rgb(0,255,0),hit_type,&attack,secondary_attack,swing);
animator.add_animation(&defender,"defend",def->first,att->first,damage,true,false,text ,display::rgb(255,0,0),hit_type,&attack,secondary_attack,swing);
for (std::vector<std::pair<const config *, map_location> >::iterator itor = leaders.cfgs.begin(); itor != leaders.cfgs.end(); itor++) {
if(itor->second == a) continue;
@ -301,7 +301,7 @@ void unit_attack(
unit_map::iterator leader = units.find(itor->second);
assert(leader != units.end());
leader->second.set_facing(itor->second.get_relative_dir(a));
animator.add_animation(&leader->second,"leading",itor->second,damage,true,false,"",0,hit_type,&attack,secondary_attack,swing);
animator.add_animation(&leader->second,"leading",itor->second,att->first,damage,true,false,"",0,hit_type,&attack,secondary_attack,swing);
}
for (std::vector<std::pair<const config *, map_location> >::iterator itor = helpers.cfgs.begin(); itor != helpers.cfgs.end(); itor++) {
if(itor->second == a) continue;
@ -309,7 +309,7 @@ void unit_attack(
unit_map::iterator helper = units.find(itor->second);
assert(helper != units.end());
helper->second.set_facing(itor->second.get_relative_dir(b));
animator.add_animation(&helper->second,"resistance",itor->second,damage,true,false,"",0,hit_type,&attack,secondary_attack,swing);
animator.add_animation(&helper->second,"resistance",itor->second,def->first,damage,true,false,"",0,hit_type,&attack,secondary_attack,swing);
}
}
@ -335,20 +335,29 @@ void unit_attack(
}
void unit_recruited(map_location& loc)
void unit_recruited(const map_location& loc,const map_location& leader_loc)
{
game_display* disp = game_display::get_singleton();
if(!disp || disp->video().update_locked() ||disp->fogged(loc)) return;
unit_map::iterator u = disp->get_units().find(loc);
if(u == disp->get_units().end()) return;
u->second.set_hidden(true);
disp->scroll_to_tile(loc,game_display::ONSCREEN,true,false);
unit_animator animator;
if(leader_loc != map_location::null_location) {
unit_map::iterator leader = disp->get_units().find(leader_loc);
if(leader == disp->get_units().end()) return;
disp->scroll_to_tiles(loc,leader_loc,game_display::ONSCREEN,true,0.0,false);
leader->second.set_facing(leader_loc.get_relative_dir(loc));
animator.add_animation(&leader->second,"recruiting",leader_loc,loc);
} else {
disp->scroll_to_tile(loc,game_display::ONSCREEN,true,false);
}
disp->draw();
u->second.set_hidden(false);
u->second.set_facing(static_cast<map_location::DIRECTION>(rand()%map_location::NDIRECTIONS));
unit_animator animator;
animator.add_animation(&u->second,"recruited",loc);
animator.add_animation(&u->second,"recruited",loc,leader_loc);
animator.start_animations();
animator.wait_for_end();
animator.set_all_standing();
@ -367,12 +376,12 @@ void unit_healing(unit& healed,map_location& healed_loc, std::vector<unit_map::i
for(std::vector<unit_map::iterator>::iterator heal_anim_it = healers.begin(); heal_anim_it != healers.end(); ++heal_anim_it) {
(*heal_anim_it)->second.set_facing((*heal_anim_it)->first.get_relative_dir(healed_loc));
animator.add_animation(&(*heal_anim_it)->second,"healing",(*heal_anim_it)->first,healing);
animator.add_animation(&(*heal_anim_it)->second,"healing",(*heal_anim_it)->first,healed_loc,healing);
}
if (healing < 0) {
animator.add_animation(&healed,"poisoned",healed_loc,-healing,false,false,lexical_cast<std::string>(-healing), display::rgb(255,0,0));
animator.add_animation(&healed,"poisoned",healed_loc,map_location::null_location,-healing,false,false,lexical_cast<std::string>(-healing), display::rgb(255,0,0));
} else {
animator.add_animation(&healed,"healed",healed_loc,healing,false,false,lexical_cast<std::string>(healing), display::rgb(0,255,0));
animator.add_animation(&healed,"healed",healed_loc,map_location::null_location,healing,false,false,lexical_cast<std::string>(healing), display::rgb(0,255,0));
}
animator.start_animations();
animator.wait_for_end();
@ -450,15 +459,18 @@ void wml_animation_internal(unit_animator & animator,const vconfig &cfg, const g
}
disp->scroll_to_tile(u->first, game_display::ONSCREEN,true,false);
vconfig t_filter = cfg.child("facing");
map_location secondary_loc = map_location::null_location;
if(!t_filter.empty()) {
terrain_filter filter(t_filter,map,game_status,units);
std::set<map_location> locs;
filter.get_locations(locs);
if(!locs.empty()) {
u->second.set_facing(u->first.get_relative_dir(*locs.begin()));
map_location::DIRECTION dir =u->first.get_relative_dir(*locs.begin());
u->second.set_facing(dir);
secondary_loc = u->first.get_direction(dir);
}
}
animator.add_animation(&u->second,cfg["flag"],u->first,lexical_cast_default<int>(cfg["value"]),utils::string_bool(cfg["with_bars"]),
animator.add_animation(&u->second,cfg["flag"],u->first,secondary_loc,lexical_cast_default<int>(cfg["value"]),utils::string_bool(cfg["with_bars"]),
false,cfg["text"],text_color, hits,primary,secondary,0);
}
const vconfig::child_list sub_anims = cfg.get_children("animate");

View file

@ -46,7 +46,7 @@ void move_unit(const std::vector<map_location>& path, unit& u, const std::vector
*
* Note: this only shows the effect, it doesn't actually kill the unit.
*/
void unit_die( const map_location& loc, unit& u, const attack_type* attack=NULL, const attack_type*secondary_attack=NULL, unit * winner=NULL);
void unit_die( const map_location& loc, unit& u, const attack_type* attack=NULL, const attack_type*secondary_attack=NULL,const map_location& winner_loc = map_location::null_location, unit * winner=NULL);
/**
* Make the unit on tile 'a' attack the unit on tile 'b'.
@ -61,7 +61,9 @@ void unit_attack(
const map_location& a, const map_location& b, int damage,
const attack_type& attack, const attack_type* secondary_attack,
int swing,std::string hit_text,bool drain,std::string att_text);
void unit_recruited(map_location& loc);
void unit_recruited(const map_location& loc,const map_location& leader_loc=map_location::null_location);
/**
* Set healer_loc to an invalid location if there are no healers.