unit_animation.cpp

Go to the documentation of this file.
00001 /* $Id: unit_animation.cpp 26727 2008-05-19 21:03:40Z boucman $ */
00002 /*
00003    Copyright (C) 2006 - 2008 by Jeremy Rosen <jeremy.rosen@enst-bretagne.fr>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013    */
00014 
00015 #include "global.hpp"
00016 
00017 #include "color_range.hpp"
00018 #include "game_display.hpp"
00019 #include "game_config.hpp"
00020 #include "gettext.hpp"
00021 #include "log.hpp"
00022 #include "halo.hpp"
00023 #include "pathutils.hpp"
00024 #include "unit.hpp"
00025 #include "unit_animation.hpp"
00026 #include "unit_types.hpp"
00027 #include "util.hpp"
00028 #include "variable.hpp"
00029 #include "sound.hpp"
00030 #include "serialization/string_utils.hpp"
00031 
00032 #include <algorithm>
00033 #include <climits>
00034 #include <cstdlib>
00035 #include <iostream>
00036 
00037 config unit_animation::prepare_animation(const config &cfg,const std::string animation_tag)
00038 {
00039     config expanded_animations;
00040     std::vector<config> unexpanded_anims;
00041     {
00042         // store all the anims we have to analyze
00043         config::const_child_itors all_anims = cfg.child_range(animation_tag);
00044         config::const_child_iterator current_anim;
00045         for(current_anim = all_anims.first; current_anim != all_anims.second ; current_anim++) {
00046             unexpanded_anims.push_back(**current_anim);
00047         }
00048     }
00049     while(!unexpanded_anims.empty()) {
00050         // take one anim out of the unexpanded list
00051         const config analyzed_anim = unexpanded_anims.back();
00052         unexpanded_anims.pop_back();
00053         config::all_children_iterator child = analyzed_anim.ordered_begin();
00054         config expanded_anim;
00055         expanded_anim.values =  analyzed_anim.values;
00056         while(child != analyzed_anim.ordered_end()) {
00057             if(*(*child).first == "if") {
00058                 std::vector<config> to_add;
00059                 config expanded_chunk = expanded_anim;
00060                 // add the content of if
00061                 expanded_chunk.append(*(*child).second);
00062                 to_add.push_back(expanded_chunk);
00063                 child++;
00064                 if(child != analyzed_anim.ordered_end() && *(*child).first == "else") {
00065                     while(child != analyzed_anim.ordered_end() && *(*child).first == "else") {
00066                         expanded_chunk = expanded_anim;
00067                         // add the content of else to the stored one
00068                         expanded_chunk.append(*(*child).second);
00069                         to_add.push_back(expanded_chunk);
00070                         // store the partially expanded string for later analyzis
00071                         child++;
00072                     }
00073 
00074                 } else {
00075                     // add an anim with the if part removed
00076                     to_add.push_back(expanded_anim);
00077                 }
00078                 // copy the end of the anim "as is" other if will be treated later
00079                 while(child != analyzed_anim.ordered_end()) {
00080                     for(std::vector<config>::iterator itor= to_add.begin(); itor != to_add.end();itor++) {
00081                         itor->add_child(*(*child).first,*(*child).second);
00082 
00083                     }
00084                     child++;
00085                 }
00086                 unexpanded_anims.insert(unexpanded_anims.end(),to_add.begin(),to_add.end());
00087             } else {
00088                 // add the current node
00089                 expanded_anim.add_child(*(*child).first,*(*child).second);
00090                 child++;
00091                 if(child == analyzed_anim.ordered_end())
00092                     expanded_animations.add_child(animation_tag,expanded_anim);
00093             }
00094         }
00095     }
00096     return expanded_animations;
00097 }
00098 
00099 unit_animation::unit_animation(int start_time,
00100     const unit_frame & frame, const std::string& event, const int variation) :
00101         terrain_types_(),
00102         unit_filter_(),
00103         secondary_unit_filter_(),
00104         directions_(),
00105         frequency_(0),
00106         base_score_(variation), 
00107         event_(utils::split(event)),
00108         value_(),
00109         primary_attack_filter_(),
00110         secondary_attack_filter_(),
00111         hits_(),
00112         swing_num_(),
00113         sub_anims_(),
00114         unit_anim_(start_time)
00115 {
00116     add_frame(frame.duration(),frame,!frame.does_not_change());
00117 }
00118 
00119 unit_animation::unit_animation(const config& cfg,const std::string frame_string ) :
00120     terrain_types_(t_translation::read_list(cfg["terrain"])),
00121     unit_filter_(),
00122     secondary_unit_filter_(),
00123     directions_(),
00124     frequency_(0),
00125     base_score_(0),
00126     event_(),
00127     value_(),
00128     primary_attack_filter_(),
00129     secondary_attack_filter_(),
00130     hits_(),
00131     swing_num_(),
00132     sub_anims_(),
00133     unit_anim_(cfg,frame_string)
00134 {
00135 //  if(!cfg["debug"].empty()) printf("DEBUG WML: FINAL\n%s\n\n",cfg.debug().c_str());
00136     config::child_map::const_iterator frame_itor =cfg.all_children().begin();
00137     for( /*null*/; frame_itor != cfg.all_children().end() ; frame_itor++) {
00138         if(frame_itor->first == frame_string) continue;
00139         if(frame_itor->first.find("_frame",frame_itor->first.size() -6 ) == std::string::npos) continue;
00140         sub_anims_[frame_itor->first] = particule(cfg,frame_itor->first.substr(0,frame_itor->first.size() -5));
00141     }
00142     event_ =utils::split(cfg["apply_to"]);
00143 
00144     const std::vector<std::string>& my_directions = utils::split(cfg["direction"]);
00145     for(std::vector<std::string>::const_iterator i = my_directions.begin(); i != my_directions.end(); ++i) {
00146         const gamemap::location::DIRECTION d = gamemap::location::parse_direction(*i);
00147         directions_.push_back(d);
00148     }
00149     config::const_child_iterator itor;
00150     for(itor = cfg.child_range("filter").first; itor <cfg.child_range("filter").second;itor++) {
00151         unit_filter_.push_back(**itor);
00152     }
00153     // FIXME OBSOLETE: Remove in 1.5.3
00154     for(itor = cfg.child_range("unit_filter").first; itor <cfg.child_range("unit_filter").second;itor++) {
00155         unit_filter_.push_back(**itor);
00156     }
00157 
00158     for(itor = cfg.child_range("secondary_unit_filter").first; itor <cfg.child_range("secondary_unit_filter").second;itor++) {
00159         secondary_unit_filter_.push_back(**itor);
00160     }
00161     // FIXME OBSOLETE: Remove in 1.5.3
00162     for(itor = cfg.child_range("filter_second").first; itor <cfg.child_range("filter_second").second;itor++) {
00163         secondary_unit_filter_.push_back(**itor);
00164     }
00165     frequency_ = atoi(cfg["frequency"].c_str());
00166 
00167     std::vector<std::string> value_str = utils::split(cfg["value"]);
00168     std::vector<std::string>::iterator value;
00169     for(value=value_str.begin() ; value != value_str.end() ; value++) {
00170         value_.push_back(atoi(value->c_str()));
00171     }
00172 
00173     std::vector<std::string> hits_str = utils::split(cfg["hits"]);
00174     std::vector<std::string>::iterator hit;
00175     for(hit=hits_str.begin() ; hit != hits_str.end() ; hit++) {
00176         if(*hit == "yes" || *hit == "hit") {
00177             hits_.push_back(HIT);
00178         }
00179         if(*hit == "no" || *hit == "miss") {
00180             hits_.push_back(MISS);
00181         }
00182         if(*hit == "yes" || *hit == "kill" ) {
00183             hits_.push_back(KILL);
00184         }
00185     }
00186     std::vector<std::string> swing_str = utils::split(cfg["swing"]);
00187     std::vector<std::string>::iterator swing;
00188     for(swing=swing_str.begin() ; swing != swing_str.end() ; swing++) {
00189         swing_num_.push_back(atoi(swing->c_str()));
00190     }
00191     for(itor = cfg.child_range("filter_attack").first; itor <cfg.child_range("filter_attack").second;itor++) {
00192         primary_attack_filter_.push_back(**itor);
00193     }
00194     // FIXME OBSOLETE: Remove in 1.5,3
00195     for(itor = cfg.child_range("attack_filter").first; itor <cfg.child_range("attack_filter").second;itor++) {
00196         primary_attack_filter_.push_back(**itor);
00197     }
00198     for(itor = cfg.child_range("filter_second_attack").first; itor <cfg.child_range("filter_second_attack").second;itor++) {
00199         secondary_attack_filter_.push_back(**itor);
00200     }
00201     // FIXME OBSOLETE: Remove in 1.5,3
00202     for(itor = cfg.child_range("secondary_attack_filter").first; itor <cfg.child_range("secondary_attack_filter").second;itor++) {
00203         secondary_attack_filter_.push_back(**itor);
00204     }
00205 
00206 }
00207 
00208 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
00209 {
00210     int result = base_score_;
00211     if(!event.empty()&&!event_.empty()) {
00212         if (std::find(event_.begin(),event_.end(),event)== event_.end()) {
00213             return MATCH_FAIL;
00214         } else {
00215             result ++;
00216         }
00217     }
00218     if(terrain_types_.empty() == false) {
00219         if(t_translation::terrain_matches(disp.get_map().get_terrain(loc), terrain_types_)) {
00220             result ++;
00221         } else {
00222             return MATCH_FAIL;
00223         }
00224     }
00225 
00226     if(value_.empty() == false ) {
00227         if (std::find(value_.begin(),value_.end(),value)== value_.end()) {
00228             return MATCH_FAIL;
00229         } else {
00230             result ++;
00231         }
00232     }
00233     if(my_unit) {
00234         if(directions_.empty()== false) {
00235             if (std::find(directions_.begin(),directions_.end(),my_unit->facing())== directions_.end()) {
00236                 return MATCH_FAIL;
00237             } else {
00238                 result ++;
00239             }
00240         }
00241         std::vector<config>::const_iterator myitor;
00242         for(myitor = unit_filter_.begin(); myitor != unit_filter_.end(); myitor++) {
00243             if(!my_unit->matches_filter(&(*myitor),loc)) return MATCH_FAIL;
00244             result++;
00245         }
00246         if(!secondary_unit_filter_.empty()) {
00247             const gamemap::location facing_loc = loc.get_direction(my_unit->facing());
00248             unit_map::const_iterator unit;
00249             for(unit=disp.get_const_units().begin() ; unit != disp.get_const_units().end() ; unit++) {
00250                 if(unit->first == facing_loc) {
00251                     std::vector<config>::const_iterator second_itor;
00252                     for(second_itor = secondary_unit_filter_.begin(); second_itor != secondary_unit_filter_.end(); second_itor++) {
00253                         if(!unit->second.matches_filter(&(*second_itor),facing_loc)) return MATCH_FAIL;
00254                         result++;
00255                     }
00256 
00257                     break;
00258                 }
00259             }
00260             if(unit == disp.get_const_units().end()) return MATCH_FAIL;
00261         }
00262 
00263     } else if (!unit_filter_.empty()) return MATCH_FAIL;
00264     if(frequency_ && !(rand()%frequency_)) return MATCH_FAIL;
00265 
00266 
00267     if(hits_.empty() == false ) {
00268         if (std::find(hits_.begin(),hits_.end(),hit)== hits_.end()) {
00269             return MATCH_FAIL;
00270         } else {
00271             result ++;
00272         }
00273     }
00274     if(swing_num_.empty() == false ) {
00275         if (std::find(swing_num_.begin(),swing_num_.end(),swing_num)== swing_num_.end()) {
00276             return MATCH_FAIL;
00277         } else {
00278             result ++;
00279         }
00280     }
00281     if(!attack) {
00282         if(!primary_attack_filter_.empty())
00283             return MATCH_FAIL;
00284     }
00285     std::vector<config>::const_iterator myitor;
00286     for(myitor = primary_attack_filter_.begin(); myitor != primary_attack_filter_.end(); myitor++) {
00287         if(!attack->matches_filter(*myitor)) return MATCH_FAIL;
00288         result++;
00289     }
00290     if(!second_attack) {
00291         if(!secondary_attack_filter_.empty())
00292             return MATCH_FAIL;
00293     }
00294     for(myitor = secondary_attack_filter_.begin(); myitor != secondary_attack_filter_.end(); myitor++) {
00295         if(!second_attack->matches_filter(*myitor)) return MATCH_FAIL;
00296         result++;
00297     }
00298     return result;
00299 
00300 }
00301 
00302 
00303 void unit_animation::fill_initial_animations( std::vector<unit_animation> & animations, const config & cfg)
00304 {
00305     const image::locator default_image = image::locator(cfg["image"]);
00306     std::vector<unit_animation>  animation_base;
00307     std::vector<unit_animation>::const_iterator itor;
00308     add_anims(animations,cfg);
00309     for(itor = animations.begin(); itor != animations.end() ; itor++) {
00310         if (std::find(itor->event_.begin(),itor->event_.end(),"default")!= itor->event_.end()) {
00311             animation_base.push_back(*itor);
00312             animation_base.back().base_score_ = unit_animation::DEFAULT_ANIM;
00313             animation_base.back().event_.clear();
00314         }
00315     }
00316     if( animation_base.empty() )
00317         animation_base.push_back(unit_animation(0,frame_builder().image(default_image).duration(600),"",unit_animation::DEFAULT_ANIM));
00318 
00319     animations.push_back(unit_animation(0,frame_builder().image(default_image).duration(1),"_disabled_",0));
00320     animations.push_back(unit_animation(0,frame_builder().image(default_image).duration(1).
00321                     blend("0.0~0.3:100,0.3~0.0:200",display::rgb(255,255,255)),"_disabled_selected_",0));
00322     for(itor = animation_base.begin() ; itor != animation_base.end() ; itor++ ) {
00323         unit_animation tmp_anim = *itor;
00324         // provide all default anims
00325         //no event, providing a catch all anim
00326         tmp_anim.unit_anim_.remove_frames_after(600);
00327         animations.push_back(tmp_anim);
00328 
00329         tmp_anim = *itor;
00330         tmp_anim.event_ = utils::split("standing");
00331         animations.push_back(tmp_anim);
00332 
00333         tmp_anim = *itor;
00334         tmp_anim.unit_anim_.override(0,"","0.0~0.3:100,0.3~0.0:200",display::rgb(255,255,255));
00335         tmp_anim.event_ = utils::split("selected");
00336         animations.push_back(tmp_anim);
00337 
00338         tmp_anim = *itor;
00339         tmp_anim.unit_anim_.override(0,"0~1:600");
00340         tmp_anim.event_ = utils::split("recruited");
00341         tmp_anim.unit_anim_.remove_frames_after(600);
00342         animations.push_back(tmp_anim);
00343 
00344         tmp_anim = *itor;
00345         tmp_anim.unit_anim_.override(0,"","1~0:600",display::rgb(255,255,255));
00346         tmp_anim.event_ = utils::split("levelin");
00347         tmp_anim.unit_anim_.remove_frames_after(600);
00348         animations.push_back(tmp_anim);
00349 
00350         tmp_anim = *itor;
00351         tmp_anim.unit_anim_.override(0,"","0~1:600,1",display::rgb(255,255,255));
00352         tmp_anim.event_ = utils::split("levelout");
00353         tmp_anim.unit_anim_.remove_frames_after(600);
00354         animations.push_back(tmp_anim);
00355 
00356         tmp_anim = *itor;
00357         tmp_anim.unit_anim_.override(0,"","",0,"0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,");
00358         tmp_anim.event_ = utils::split("movement");
00359         animations.push_back(tmp_anim);
00360 
00361         tmp_anim = *itor;
00362         tmp_anim.unit_anim_.override(-150);
00363         tmp_anim.event_ = utils::split("defend");
00364         animations.push_back(tmp_anim);
00365 
00366         tmp_anim = *itor;
00367         tmp_anim.unit_anim_.override(-150,"","",0,"0~0.6:150,0.6~0:150");
00368         tmp_anim.event_ = utils::split("attack");
00369         tmp_anim.primary_attack_filter_.push_back(config());
00370         tmp_anim.primary_attack_filter_.back()["range"] = "melee";
00371         animations.push_back(tmp_anim);
00372 
00373         tmp_anim = *itor;
00374         tmp_anim.unit_anim_.override(-150);
00375         tmp_anim.event_ = utils::split("attack");
00376         tmp_anim.primary_attack_filter_.push_back(config());
00377         tmp_anim.primary_attack_filter_.back()["range"] = "ranged";
00378         animations.push_back(tmp_anim);
00379 
00380         tmp_anim = *itor;
00381         tmp_anim.unit_anim_.override(0,"1~0:600");
00382         tmp_anim.unit_anim_.remove_frames_after(600);
00383         tmp_anim.event_ = utils::split("death");
00384         animations.push_back(tmp_anim);
00385         animations.back().sub_anims_["_death_sound"] = particule();
00386         animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder());
00387         animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder().sound(cfg["die_sound"]),true);
00388 
00389 
00390         tmp_anim = *itor;
00391         tmp_anim.unit_anim_.override(0,"1~0:150");
00392         tmp_anim.unit_anim_.remove_frames_after(150);
00393         tmp_anim.event_ = utils::split("pre_teleport");
00394         animations.push_back(tmp_anim);
00395 
00396         tmp_anim = *itor;
00397         tmp_anim.unit_anim_.override(0,"0~1:150,1");
00398         tmp_anim.unit_anim_.remove_frames_after(150);
00399         tmp_anim.event_ = utils::split("post_teleport");
00400         animations.push_back(tmp_anim);
00401 
00402         tmp_anim = *itor;
00403         tmp_anim.unit_anim_.override(0,"","0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30",display::rgb(255,255,255));
00404         tmp_anim.unit_anim_.remove_frames_after(300);
00405         tmp_anim.event_ = utils::split("healed");
00406         animations.push_back(tmp_anim);
00407         animations.back().sub_anims_["_healed_sound"] = particule();
00408         animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder());
00409         animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder().sound("heal.wav"),true);
00410 
00411         tmp_anim = *itor;
00412         tmp_anim.unit_anim_.override(0,"","0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30",display::rgb(0,255,0));
00413         tmp_anim.unit_anim_.remove_frames_after(300);
00414         tmp_anim.event_ = utils::split("poisoned");
00415         animations.push_back(tmp_anim);
00416         animations.back().sub_anims_["_poison_sound"] = particule();
00417         animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder());
00418         animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound("poison.ogg"),true);
00419 
00420     }
00421 
00422 }
00423 void unit_animation::add_anims( std::vector<unit_animation> & animations, const config & cfg)
00424 {
00425     config expanded_cfg;
00426     config::child_list::const_iterator anim_itor;
00427 
00428     expanded_cfg = unit_animation::prepare_animation(cfg,"animation");
00429     const config::child_list& parsed_animations = expanded_cfg.get_children("animation");
00430     for(anim_itor = parsed_animations.begin(); anim_itor != parsed_animations.end(); ++anim_itor) {
00431         animations.push_back(unit_animation(**anim_itor));
00432     }
00433 
00434 
00435     expanded_cfg = unit_animation::prepare_animation(cfg,"leading_anim");
00436     const config::child_list& leading_anims = expanded_cfg.get_children("leading_anim");
00437     for(anim_itor = leading_anims.begin(); anim_itor != leading_anims.end(); ++anim_itor) {
00438         (**anim_itor)["apply_to"] ="leading";
00439         animations.push_back(unit_animation(**anim_itor));
00440     }
00441     expanded_cfg = unit_animation::prepare_animation(cfg,"recruit_anim");
00442     const config::child_list& recruit_anims = expanded_cfg.get_children("recruit_anim");
00443     for(anim_itor = recruit_anims.begin(); anim_itor != recruit_anims.end(); ++anim_itor) {
00444         (**anim_itor)["apply_to"] ="recruited";
00445         animations.push_back(unit_animation(**anim_itor));
00446     }
00447     expanded_cfg = unit_animation::prepare_animation(cfg,"standing_anim");
00448     const config::child_list& standing_anims = expanded_cfg.get_children("standing_anim");
00449     for(anim_itor = standing_anims.begin(); anim_itor != standing_anims.end(); ++anim_itor) {
00450         (**anim_itor)["apply_to"] ="standing,default";
00451         animations.push_back(unit_animation(**anim_itor));
00452     }
00453     expanded_cfg = unit_animation::prepare_animation(cfg,"idle_anim");
00454     const config::child_list& idle_anims = expanded_cfg.get_children("idle_anim");
00455     for(anim_itor = idle_anims.begin(); anim_itor != idle_anims.end(); ++anim_itor) {
00456         (**anim_itor)["apply_to"] ="idling";
00457         animations.push_back(unit_animation(**anim_itor));
00458     }
00459     expanded_cfg = unit_animation::prepare_animation(cfg,"levelin_anim");
00460     const config::child_list& levelin_anims = expanded_cfg.get_children("levelin_anim");
00461     for(anim_itor = levelin_anims.begin(); anim_itor != levelin_anims.end(); ++anim_itor) {
00462         (**anim_itor)["apply_to"] ="levelin";
00463         animations.push_back(unit_animation(**anim_itor));
00464     }
00465     expanded_cfg = unit_animation::prepare_animation(cfg,"levelout_anim");
00466     const config::child_list& levelout_anims = expanded_cfg.get_children("levelout_anim");
00467     for(anim_itor = levelout_anims.begin(); anim_itor != levelout_anims.end(); ++anim_itor) {
00468         (**anim_itor)["apply_to"] ="levelout";
00469         animations.push_back(unit_animation(**anim_itor));
00470     }
00471     expanded_cfg = unit_animation::prepare_animation(cfg,"healing_anim");
00472     const config::child_list& healing_anims = expanded_cfg.get_children("healing_anim");
00473     for(anim_itor = healing_anims.begin(); anim_itor != healing_anims.end(); ++anim_itor) {
00474         (**anim_itor)["apply_to"] ="healing";
00475         (**anim_itor)["value"]=(**anim_itor)["damage"];
00476         animations.push_back(unit_animation(**anim_itor));
00477     }
00478     expanded_cfg = unit_animation::prepare_animation(cfg,"healed_anim");
00479     const config::child_list& healed_anims = expanded_cfg.get_children("healed_anim");
00480     for(anim_itor = healed_anims.begin(); anim_itor != healed_anims.end(); ++anim_itor) {
00481         (**anim_itor)["apply_to"] ="healed";
00482         (**anim_itor)["value"]=(**anim_itor)["healing"];
00483         animations.push_back(unit_animation(**anim_itor));
00484         animations.back().sub_anims_["_healed_sound"] = particule();
00485         animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder());
00486         animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder().sound("heal.wav"),true);
00487     }
00488     expanded_cfg = unit_animation::prepare_animation(cfg,"poison_anim");
00489     const config::child_list& poison_anims = expanded_cfg.get_children("poison_anim");
00490     for(anim_itor = poison_anims.begin(); anim_itor != poison_anims.end(); ++anim_itor) {
00491         (**anim_itor)["apply_to"] ="poisoned";
00492         (**anim_itor)["value"]=(**anim_itor)["damage"];
00493         animations.push_back(unit_animation(**anim_itor));
00494         animations.back().sub_anims_["_poison_sound"] = particule();
00495         animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder());
00496         animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound("poison.ogg"),true);
00497     }
00498     expanded_cfg = unit_animation::prepare_animation(cfg,"movement_anim");
00499     const config::child_list& movement_anims = expanded_cfg.get_children("movement_anim");
00500     for(anim_itor = movement_anims.begin(); anim_itor != movement_anims.end(); ++anim_itor) {
00501         if((**anim_itor)["offset"].empty() ) {
00502             (**anim_itor)["offset"] ="0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,0~1:150,";
00503 
00504         }
00505         (**anim_itor)["apply_to"] ="movement";
00506         animations.push_back(unit_animation(**anim_itor));
00507     }
00508     expanded_cfg = unit_animation::prepare_animation(cfg,"defend");
00509     const config::child_list& defends = expanded_cfg.get_children("defend");
00510     for(anim_itor = defends.begin(); anim_itor != defends.end(); ++anim_itor) {
00511         (**anim_itor)["apply_to"] ="defend";
00512         if(!(**anim_itor)["damage"].empty()) {
00513             (**anim_itor)["value"]=(**anim_itor)["damage"];
00514             animations.push_back(unit_animation(**anim_itor));
00515             if(atoi((**anim_itor)["value"].c_str()) != 0) {
00516                 animations.back().add_frame(100,frame_builder()
00517                             .image(animations.back().get_last_frame().parameters(0).image)
00518                             .duration(100)
00519                             .blend("0.5:50,0.0:50",game_display::rgb(255,0,0)));
00520             }
00521         } else {
00522             (**anim_itor)["value"]="0";
00523             animations.push_back(unit_animation(**anim_itor));
00524             (**anim_itor)["value"]="";
00525             animations.push_back(unit_animation(**anim_itor));
00526                 animations.back().add_frame(100,frame_builder()
00527                             .image(animations.back().get_last_frame().parameters(0).image)
00528                             .duration(100)
00529                             .blend("0.5:50,0.0:50",game_display::rgb(255,0,0)));
00530         }
00531     }
00532     expanded_cfg = unit_animation::prepare_animation(cfg,"attack_anim");
00533     const config::child_list& attack_anims = expanded_cfg.get_children("attack_anim");
00534     for(config::child_list::const_iterator d = attack_anims.begin(); d != attack_anims.end(); ++d) {
00535         (**d)["apply_to"] ="attack";
00536         if((**d)["offset"].empty() && (**d).get_children("missile_frame").empty()) {
00537             (**d)["offset"] ="0~0.6,0.6~0";
00538         }
00539         if(!(**d).get_children("missile_frame").empty()) {
00540             if( (**d)["missile_offset"].empty())(**d)["missile_offset"] = "0~0.8";
00541             config tmp;
00542             tmp["duration"]="1";
00543             (**d).add_child("missile_frame",tmp);
00544             (**d).add_child_at("missile_frame",tmp,0);
00545         }
00546 
00547         animations.push_back(unit_animation(**d));
00548     }
00549     // always have an attack animation
00550     expanded_cfg = unit_animation::prepare_animation(cfg,"death");
00551     const config::child_list& deaths = expanded_cfg.get_children("death");
00552     for(anim_itor = deaths.begin(); anim_itor != deaths.end(); ++anim_itor) {
00553         (**anim_itor)["apply_to"] ="death";
00554         animations.push_back(unit_animation(**anim_itor));
00555         image::locator image_loc = animations.back().get_last_frame().parameters(0).image;
00556         animations.back().add_frame(600,frame_builder().image(image_loc).duration(600).highlight("1~0:600"));
00557         if(!cfg["die_sound"].empty()) {
00558             animations.back().sub_anims_["_death_sound"] = particule();
00559             animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder());
00560             animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder().sound(cfg["die_sound"]),true);
00561         }
00562     }
00563     // Always have a defensive animation
00564     expanded_cfg = unit_animation::prepare_animation(cfg,"victory_anim");
00565     const config::child_list& victory_anims = expanded_cfg.get_children("victory_anim");
00566     for(anim_itor = victory_anims.begin(); anim_itor != victory_anims.end(); ++anim_itor) {
00567         (**anim_itor)["apply_to"] ="victory";
00568         animations.push_back(unit_animation(**anim_itor));
00569     }
00570     // Always have a victory animation
00571     expanded_cfg = unit_animation::prepare_animation(cfg,"extra_anim");
00572     const config::child_list& extra_anims = expanded_cfg.get_children("extra_anim");
00573     for(anim_itor = extra_anims.begin(); anim_itor != extra_anims.end(); ++anim_itor) {
00574         (**anim_itor)["apply_to"] =(**anim_itor)["flag"];
00575         animations.push_back(unit_animation(**anim_itor));
00576     }
00577     expanded_cfg = unit_animation::prepare_animation(cfg,"teleport_anim");
00578     const config::child_list& teleports = expanded_cfg.get_children("teleport_anim");
00579     for(anim_itor = teleports.begin(); anim_itor != teleports.end(); ++anim_itor) {
00580         (**anim_itor)["apply_to"] ="pre_teleport";
00581         animations.push_back(unit_animation(**anim_itor));
00582         animations.back().unit_anim_.remove_frames_after(0);
00583         (**anim_itor)["apply_to"] ="post_teleport";
00584         animations.push_back(unit_animation(**anim_itor));
00585         animations.back().unit_anim_.remove_frames_until(0);
00586     }
00587 
00588 }
00589 
00590 void unit_animation::particule::override( int start_time,const std::string highlight,const std::string blend_ratio ,Uint32 blend_color ,const std::string offset) 
00591 {
00592     set_begin_time(start_time);
00593     if(!highlight.empty()) parameters_.highlight(highlight);
00594     if(!offset.empty()) parameters_.offset(offset);
00595     if(!blend_ratio.empty()) parameters_.blend(blend_ratio,blend_color);
00596     
00597 
00598 }
00599 
00600 bool unit_animation::particule::need_update() const
00601 {
00602     if(animated<unit_frame>::need_update()) return true;
00603     if(get_current_frame().need_update()) return true;
00604     if(parameters_.need_update()) return true;
00605     return false;
00606 }
00607 
00608 unit_animation::particule::particule(
00609     const config& cfg, const std::string frame_string ) :
00610         animated<unit_frame>(),
00611         accelerate(true),
00612         parameters_(cfg,frame_string),
00613         src_(),
00614         dst_(),
00615         halo_id_(0),
00616         last_frame_begin_time_(0)
00617 {
00618     config::const_child_itors range = cfg.child_range(frame_string+"frame");
00619     config::const_child_iterator itor;
00620     starting_frame_time_=INT_MAX;
00621     if(cfg[frame_string+"start_time"].empty() &&range.first != range.second) {
00622         for(itor = range.first; itor != range.second; itor++) {
00623             starting_frame_time_=minimum(starting_frame_time_,atoi((**itor)["begin"].c_str()));
00624         }
00625     } else {
00626         starting_frame_time_ = atoi(cfg[frame_string+"start_time"].c_str());
00627     }
00628 
00629     for(; range.first != range.second; ++range.first) {
00630         unit_frame tmp_frame(**range.first);
00631         add_frame(tmp_frame.duration(),tmp_frame,!tmp_frame.does_not_change());
00632     }
00633     parameters_.duration(get_animation_duration());
00634     if(!parameters_.does_not_change()  ) {
00635             force_change();
00636     }
00637 }
00638 
00639 bool unit_animation::need_update() const
00640 {
00641     if(unit_anim_.need_update()) return true;
00642     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00643     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00644         if(anim_itor->second.need_update()) return true;
00645     }
00646     return false;
00647 }
00648 
00649 bool unit_animation::animation_finished() const
00650 {
00651     if(!unit_anim_.animation_finished()) return false;
00652     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00653     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00654         if(!anim_itor->second.animation_finished()) return false;
00655     }
00656     return true;
00657 }
00658 
00659 bool unit_animation::animation_finished_potential() const
00660 {
00661     if(!unit_anim_.animation_finished_potential()) return false;
00662     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00663     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00664         if(!anim_itor->second.animation_finished_potential()) return false;
00665     }
00666     return true;
00667 }
00668 
00669 void unit_animation::update_last_draw_time() 
00670 {
00671     double acceleration = unit_anim_.accelerate ? game_display::get_singleton()->turbo_speed() : 1.0;
00672     unit_anim_.update_last_draw_time(acceleration);
00673     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00674     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00675         anim_itor->second.update_last_draw_time(acceleration);
00676     }
00677 }
00678 
00679 int unit_animation::get_end_time() const
00680 {
00681     int result = unit_anim_.get_end_time();
00682     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.end();
00683     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00684         result= minimum<int>(result,anim_itor->second.get_end_time());
00685     }
00686     return result;
00687 }
00688 
00689 int unit_animation::get_begin_time() const
00690 {
00691     int result = unit_anim_.get_begin_time();
00692     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00693     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00694         result= minimum<int>(result,anim_itor->second.get_begin_time());
00695     }
00696     return result;
00697 }
00698 
00699 void unit_animation::start_animation(int start_time,const gamemap::location &src, const gamemap::location &dst, bool cycles, const std::string text, const Uint32 text_color,const bool accelerate)
00700 {
00701         unit_anim_.accelerate = accelerate;
00702         new_animation_frame();
00703     unit_anim_.start_animation(start_time, src, dst, cycles);
00704     if(!text.empty()) {
00705         particule crude_build;
00706         crude_build.add_frame(1,frame_builder());
00707         crude_build.add_frame(1,frame_builder().text(text,text_color),true);
00708         sub_anims_["_add_text"] = crude_build;
00709     }
00710     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00711     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00712         anim_itor->second.accelerate = accelerate;
00713         anim_itor->second.start_animation(start_time,src,dst,cycles);
00714     }
00715 }
00716 void unit_animation::pause_animation()
00717 {
00718 
00719     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00720     unit_anim_.pause_animation();
00721     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00722         anim_itor->second.pause_animation();
00723     }
00724 }
00725 void unit_animation::restart_animation()
00726 {
00727 
00728     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00729     unit_anim_.restart_animation();
00730     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00731         anim_itor->second.restart_animation();
00732     }
00733 }
00734 void unit_animation::redraw(const frame_parameters& value)
00735 {
00736 
00737     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00738     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00739         anim_itor->second.redraw( value);
00740     }
00741 }
00742 void unit_animation::invalidate(const frame_parameters& value) const
00743 {
00744 
00745     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00746     unit_anim_.invalidate(value,true);
00747     for( /*null*/; anim_itor != sub_anims_.end() ; anim_itor++) {
00748         anim_itor->second.invalidate(value);
00749     }
00750 }
00751 void unit_animation::particule::redraw(const frame_parameters& value)
00752 {
00753     const unit_frame& current_frame= get_current_frame();
00754     const frame_parameters default_val = parameters_.parameters(get_animation_time() -get_begin_time());
00755     if(get_current_frame_begin_time() != last_frame_begin_time_ ) {
00756         last_frame_begin_time_ = get_current_frame_begin_time();
00757         current_frame.redraw(get_current_frame_time(),true,src_,dst_,&halo_id_,default_val,value);
00758     } else {
00759         current_frame.redraw(get_current_frame_time(),false,src_,dst_,&halo_id_,default_val,value);
00760     }
00761 }
00762 void unit_animation::particule::invalidate(const frame_parameters& value,const bool primary ) const
00763 {
00764     const unit_frame& current_frame= get_current_frame();
00765     const frame_parameters default_val = parameters_.parameters(get_animation_time() -get_begin_time());
00766     current_frame.invalidate(get_current_frame_time(),src_,dst_,default_val,value,primary);
00767 }
00768 
00769 unit_animation::particule::~particule()
00770 {
00771     halo::remove(halo_id_);
00772     halo_id_ = halo::NO_HALO;
00773 }
00774 
00775 void unit_animation::particule::start_animation(int start_time,
00776     const gamemap::location &src, const gamemap::location &dst, 
00777     bool cycles)
00778 {
00779     halo::remove(halo_id_);
00780     halo_id_ = halo::NO_HALO;
00781     parameters_.duration(get_animation_duration());
00782     animated<unit_frame>::start_animation(start_time,cycles);
00783     last_frame_begin_time_ = get_begin_time() -1;
00784     if(src != gamemap::location::null_location || dst != gamemap::location::null_location) {
00785         src_ = src;
00786         dst_ = dst;
00787     }
00788 }
00789 
00790 void unit_animator::add_animation(unit* animated_unit,const std::string& event,
00791         const gamemap::location &src , const int value,bool with_bars,bool cycles,
00792         const std::string text,const Uint32 text_color,
00793         const unit_animation::hit_type hit_type,
00794         const attack_type* attack, const attack_type* second_attack, int swing_num)
00795 {
00796     if(!animated_unit) return;
00797     anim_elem tmp;
00798     game_display*disp = game_display::get_singleton();
00799     tmp.my_unit = animated_unit;
00800     tmp.text = text;
00801     tmp.text_color = text_color;
00802     tmp.src = src;
00803     tmp.with_bars= with_bars;
00804     tmp.cycles = cycles;
00805     tmp.animation = animated_unit->choose_animation(*disp,src,event,value,hit_type,attack,second_attack,swing_num);
00806 if(!tmp.animation) return;
00807 
00808 
00809 
00810     start_time_ = maximum<int>(start_time_,tmp.animation->get_begin_time());
00811     animated_units_.push_back(tmp);
00812 }
00813 void unit_animator::replace_anim_if_invalid(unit* animated_unit,const std::string& event,
00814         const gamemap::location &src , const int value,bool with_bars,bool cycles,
00815         const std::string text,const Uint32 text_color,
00816         const unit_animation::hit_type hit_type,
00817         const attack_type* attack, const attack_type* second_attack, int swing_num)
00818 {
00819     if(!animated_unit) return;
00820     game_display*disp = game_display::get_singleton();
00821     if(animated_unit->get_animation() &&
00822             !animated_unit->get_animation()->animation_finished_potential() && 
00823             animated_unit->get_animation()->matches(*disp,src,animated_unit,event,value,hit_type,attack,second_attack,swing_num) >unit_animation::MATCH_FAIL) {
00824         anim_elem tmp;
00825         tmp.my_unit = animated_unit;
00826         tmp.text = text;
00827         tmp.text_color = text_color;
00828         tmp.src = src;
00829         tmp.with_bars= with_bars;
00830         tmp.cycles = cycles;
00831         tmp.animation = NULL;
00832         animated_units_.push_back(tmp);
00833     }else {
00834         add_animation(animated_unit,event,src,value,with_bars,cycles,text,text_color,hit_type,attack,second_attack,swing_num);
00835     }
00836 }
00837 void unit_animator::start_animations()
00838 {
00839     int begin_time = INT_MAX;
00840     std::vector<anim_elem>::iterator anim;
00841     for(anim = animated_units_.begin(); anim != animated_units_.end();anim++) {
00842            if(anim->my_unit->get_animation()) {
00843                if(anim->animation) {
00844                    begin_time = minimum<int>(begin_time,anim->animation->get_begin_time());
00845                } else  {
00846                    begin_time = minimum<int>(begin_time,anim->my_unit->get_animation()->get_begin_time());
00847                }
00848            }
00849     }
00850     for(anim = animated_units_.begin(); anim != animated_units_.end();anim++) {
00851         if(anim->animation) {
00852             anim->my_unit->start_animation(begin_time,anim->src, anim->animation,anim->with_bars, anim->cycles,anim->text,anim->text_color);
00853             anim->animation = NULL;
00854         }
00855         
00856     }
00857 }
00858 
00859 bool unit_animator::would_end() const
00860 {
00861     bool finished = true;
00862     for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();anim++) {
00863         finished &= anim->my_unit->get_animation()->animation_finished_potential();
00864     }
00865     return finished;
00866 }
00867 void unit_animator::wait_until(int animation_time) const
00868 {
00869     game_display*disp = game_display::get_singleton();
00870     double speed = disp->turbo_speed();
00871     int end_tick = animated_units_[0].my_unit->get_animation()->time_to_tick(animation_time);
00872     while (SDL_GetTicks() < (unsigned int)end_tick - 20/speed) {
00873         disp->draw();
00874                 end_tick = animated_units_[0].my_unit->get_animation()->time_to_tick(animation_time);
00875         events::pump();
00876         disp->delay(maximum<int>(0,
00877             minimum<int>(10, 
00878             static_cast<int>((animation_time - get_animation_time()) * speed))));
00879     }
00880     disp->delay(maximum<int>(0,end_tick - SDL_GetTicks() +5));
00881     new_animation_frame();
00882 }
00883 void unit_animator::wait_for_end() const
00884 {
00885     if (game_config::no_delay) return;
00886     bool finished = false;
00887     game_display*disp = game_display::get_singleton();
00888     while(!finished) {
00889         disp->draw();
00890         events::pump();
00891         disp->delay(10);
00892         finished = true;
00893         for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();anim++) {
00894             finished &= anim->my_unit->get_animation()->animation_finished_potential();
00895         }
00896     }
00897 }
00898 int unit_animator::get_animation_time() const{
00899     return animated_units_[0].my_unit->get_animation()->get_animation_time() ; 
00900 }
00901 
00902 int unit_animator::get_animation_time_potential() const{
00903     return animated_units_[0].my_unit->get_animation()->get_animation_time_potential() ; 
00904 }
00905 
00906 int unit_animator::get_end_time() const
00907 {
00908         int end_time = INT_MIN;
00909         for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();anim++) {
00910            if(anim->my_unit->get_animation()) {
00911                 end_time = maximum<int>(end_time,anim->my_unit->get_animation()->get_end_time());
00912            }
00913         }
00914         return end_time;
00915 }
00916 void unit_animator::pause_animation()
00917 {
00918         for(std::vector<anim_elem>::iterator anim = animated_units_.begin(); anim != animated_units_.end();anim++) {
00919            if(anim->my_unit->get_animation()) {
00920                 anim->my_unit->get_animation()->pause_animation();
00921            }
00922         }
00923 }
00924 void unit_animator::restart_animation()
00925 {
00926         for(std::vector<anim_elem>::iterator anim = animated_units_.begin(); anim != animated_units_.end();anim++) {
00927            if(anim->my_unit->get_animation()) {
00928                 anim->my_unit->get_animation()->restart_animation();
00929            }
00930         }
00931 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs