unit_animation.cpp

Go to the documentation of this file.
00001 /* $Id: unit_animation.cpp 48153 2011-01-01 15:57:50Z mordante $ */
00002 /*
00003    Copyright (C) 2006 - 2011 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 as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014    */
00015 
00016 #include "global.hpp"
00017 
00018 #include "unit_animation.hpp"
00019 
00020 #include "foreach.hpp"
00021 #include "game_display.hpp"
00022 #include "halo.hpp"
00023 #include "map.hpp"
00024 #include "unit.hpp"
00025 #include "variable.hpp"
00026 #include "resources.hpp"
00027 #include "play_controller.hpp"
00028 
00029 #include <algorithm>
00030 
00031 struct tag_name_manager {
00032     tag_name_manager() : names() {
00033         names.push_back("animation");
00034         names.push_back("attack_anim");
00035         names.push_back("death");
00036         names.push_back("defend");
00037         names.push_back("extra_anim");
00038         names.push_back("healed_anim");
00039         names.push_back("healing_anim");
00040         names.push_back("idle_anim");
00041         names.push_back("leading_anim");
00042         names.push_back("resistance_anim");
00043         names.push_back("levelin_anim");
00044         names.push_back("levelout_anim");
00045         names.push_back("movement_anim");
00046         names.push_back("poison_anim");
00047         names.push_back("recruit_anim");
00048         names.push_back("recruiting_anim");
00049         names.push_back("standing_anim");
00050         names.push_back("teleport_anim");
00051         names.push_back("pre_movement_anim");
00052         names.push_back("post_movement_anim");
00053         names.push_back("draw_weapon_anim");
00054         names.push_back("sheath_weapon_anim");
00055         names.push_back("victory_anim");
00056         names.push_back("_transparent"); // Used for WB
00057     }
00058     std::vector<std::string> names;
00059 };
00060 namespace {
00061     tag_name_manager anim_tags;
00062 } //end anonymous namespace
00063 
00064 const std::vector<std::string>& unit_animation::all_tag_names() {
00065     return anim_tags.names;
00066 }
00067 
00068 struct animation_branch
00069 {
00070     animation_branch()
00071         : attributes()
00072         , children()
00073     {
00074     }
00075 
00076     config attributes;
00077     std::vector<config::all_children_iterator> children;
00078     config merge() const
00079     {
00080         config result = attributes;
00081         foreach (const config::all_children_iterator &i, children)
00082             result.add_child(i->key, i->cfg);
00083         return result;
00084     }
00085 };
00086 
00087 typedef std::list<animation_branch> animation_branches;
00088 
00089 struct animation_cursor
00090 {
00091     config::all_children_itors itors;
00092     animation_branches branches;
00093     animation_cursor *parent;
00094     animation_cursor(const config &cfg):
00095         itors(cfg.all_children_range()), branches(1), parent(NULL)
00096     {
00097         branches.back().attributes.merge_attributes(cfg);
00098     }
00099     animation_cursor(const config &cfg, animation_cursor *p):
00100         itors(cfg.all_children_range()), branches(p->branches), parent(p)
00101     {
00102         foreach (animation_branch &ab, branches)
00103             ab.attributes.merge_attributes(cfg);
00104     }
00105 };
00106 
00107 static void prepare_single_animation(const config &anim_cfg, animation_branches &expanded_anims)
00108 {
00109     std::list<animation_cursor> anim_cursors;
00110     anim_cursors.push_back(animation_cursor(anim_cfg));
00111     while (!anim_cursors.empty())
00112     {
00113         animation_cursor &ac = anim_cursors.back();
00114         if (ac.itors.first == ac.itors.second) {
00115             if (!ac.parent) break;
00116             // Merge all the current branches into the parent.
00117             ac.parent->branches.splice(ac.parent->branches.end(),
00118                 ac.branches, ac.branches.begin(), ac.branches.end());
00119             anim_cursors.pop_back();
00120             continue;
00121         }
00122         if (ac.itors.first->key != "if")
00123         {
00124             // Append current config object to all the branches in scope.
00125             foreach (animation_branch &ab, ac.branches) {
00126                 ab.children.push_back(ac.itors.first);
00127             }
00128             ++ac.itors.first;
00129             continue;
00130         }
00131         int count = 0;
00132         do {
00133             /* Copies the current branches to each cursor created
00134                for the conditional clauses. Merge the attributes
00135                of the clause into them. */
00136             anim_cursors.push_back(animation_cursor(ac.itors.first->cfg, &ac));
00137             ++ac.itors.first;
00138             ++count;
00139         } while (ac.itors.first != ac.itors.second && ac.itors.first->key == "else");
00140         if (count > 1) {
00141             /* There are some "else" clauses, discard the branches
00142                from the current cursor. */
00143             ac.branches.clear();
00144         }
00145     }
00146 
00147     // Create the config object describing each branch.
00148     assert(anim_cursors.size() == 1);
00149     animation_cursor &ac = anim_cursors.back();
00150     expanded_anims.splice(expanded_anims.end(),
00151         ac.branches, ac.branches.begin(), ac.branches.end());
00152 }
00153 
00154 static animation_branches prepare_animation(const config &cfg, const std::string &animation_tag)
00155 {
00156     animation_branches expanded_animations;
00157     foreach (const config &anim, cfg.child_range(animation_tag)) {
00158         prepare_single_animation(anim, expanded_animations);
00159     }
00160     return expanded_animations;
00161 }
00162 
00163 unit_animation::unit_animation(int start_time,
00164     const unit_frame & frame, const std::string& event, const int variation, const frame_builder & builder) :
00165         terrain_types_(),
00166         unit_filter_(),
00167         secondary_unit_filter_(),
00168         directions_(),
00169         frequency_(0),
00170         base_score_(variation),
00171         event_(utils::split(event)),
00172         value_(),
00173         primary_attack_filter_(),
00174         secondary_attack_filter_(),
00175         hits_(),
00176         value2_(),
00177         sub_anims_(),
00178         unit_anim_(start_time,builder),
00179         src_(),
00180         dst_(),
00181         invalidated_(false),
00182         play_offscreen_(true),
00183         overlaped_hex_()
00184 {
00185     add_frame(frame.duration(),frame,!frame.does_not_change());
00186 }
00187 
00188 unit_animation::unit_animation(const config& cfg,const std::string& frame_string ) :
00189     terrain_types_(t_translation::read_list(cfg["terrain_type"])),
00190     unit_filter_(),
00191     secondary_unit_filter_(),
00192     directions_(),
00193     frequency_(cfg["frequency"]),
00194     base_score_(cfg["base_score"]),
00195     event_(),
00196     value_(),
00197     primary_attack_filter_(),
00198     secondary_attack_filter_(),
00199     hits_(),
00200     value2_(),
00201     sub_anims_(),
00202     unit_anim_(cfg,frame_string),
00203     src_(),
00204     dst_(),
00205     invalidated_(false),
00206     play_offscreen_(true),
00207     overlaped_hex_()
00208 {
00209 //  if(!cfg["debug"].empty()) printf("DEBUG WML: FINAL\n%s\n\n",cfg.debug().c_str());
00210     foreach (const config::any_child &fr, cfg.all_children_range())
00211     {
00212         if (fr.key == frame_string) continue;
00213         if (fr.key.find("_frame", fr.key.size() - 6) == std::string::npos) continue;
00214         if (sub_anims_.find(fr.key) != sub_anims_.end()) continue;
00215         sub_anims_[fr.key] = particule(cfg, fr.key.substr(0, fr.key.size() - 5));
00216     }
00217     event_ =utils::split(cfg["apply_to"]);
00218 
00219     const std::vector<std::string>& my_directions = utils::split(cfg["direction"]);
00220     for(std::vector<std::string>::const_iterator i = my_directions.begin(); i != my_directions.end(); ++i) {
00221         const map_location::DIRECTION d = map_location::parse_direction(*i);
00222         directions_.push_back(d);
00223     }
00224     foreach (const config &filter, cfg.child_range("filter")) {
00225         unit_filter_.push_back(filter);
00226     }
00227 
00228     foreach (const config &filter, cfg.child_range("filter_second")) {
00229         secondary_unit_filter_.push_back(filter);
00230     }
00231 
00232     std::vector<std::string> value_str = utils::split(cfg["value"]);
00233     std::vector<std::string>::iterator value;
00234     for(value=value_str.begin() ; value != value_str.end() ; ++value) {
00235         value_.push_back(atoi(value->c_str()));
00236     }
00237 
00238     std::vector<std::string> hits_str = utils::split(cfg["hits"]);
00239     std::vector<std::string>::iterator hit;
00240     for(hit=hits_str.begin() ; hit != hits_str.end() ; ++hit) {
00241         if(*hit == "yes" || *hit == "hit") {
00242             hits_.push_back(HIT);
00243         }
00244         if(*hit == "no" || *hit == "miss") {
00245             hits_.push_back(MISS);
00246         }
00247         if(*hit == "yes" || *hit == "kill" ) {
00248             hits_.push_back(KILL);
00249         }
00250     }
00251     std::vector<std::string> value2_str = utils::split(cfg["value_second"]);
00252     std::vector<std::string>::iterator value2;
00253     for(value2=value2_str.begin() ; value2 != value2_str.end() ; ++value2) {
00254         value2_.push_back(atoi(value2->c_str()));
00255     }
00256     foreach (const config &filter, cfg.child_range("filter_attack")) {
00257         primary_attack_filter_.push_back(filter);
00258     }
00259     foreach (const config &filter, cfg.child_range("filter_second_attack")) {
00260         secondary_attack_filter_.push_back(filter);
00261     }
00262     play_offscreen_ = cfg["offscreen"].to_bool(true);
00263 
00264 }
00265 
00266 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 value2) const
00267 {
00268     int result = base_score_;
00269     if(!event.empty()&&!event_.empty()) {
00270         if (std::find(event_.begin(),event_.end(),event)== event_.end()) {
00271             return MATCH_FAIL;
00272         } else {
00273             result ++;
00274         }
00275     }
00276     if(terrain_types_.empty() == false) {
00277         if(t_translation::terrain_matches(disp.get_map().get_terrain(loc), terrain_types_)) {
00278             result ++;
00279         } else {
00280             return MATCH_FAIL;
00281         }
00282     }
00283 
00284     if(value_.empty() == false ) {
00285         if (std::find(value_.begin(),value_.end(),value)== value_.end()) {
00286             return MATCH_FAIL;
00287         } else {
00288             result ++;
00289         }
00290     }
00291     if(my_unit) {
00292         if(directions_.empty()== false) {
00293             if (std::find(directions_.begin(),directions_.end(),my_unit->facing())== directions_.end()) {
00294                 return MATCH_FAIL;
00295             } else {
00296                 result ++;
00297             }
00298         }
00299         std::vector<config>::const_iterator myitor;
00300         for(myitor = unit_filter_.begin(); myitor != unit_filter_.end(); ++myitor) {
00301             if (!my_unit->matches_filter(vconfig(*myitor), loc)) return MATCH_FAIL;
00302             ++result;
00303         }
00304         if(!secondary_unit_filter_.empty()) {
00305             unit_map::const_iterator unit;
00306             for(unit=disp.get_const_units().begin() ; unit != disp.get_const_units().end() ; ++unit) {
00307                 if (unit->get_location() == second_loc) {
00308                     std::vector<config>::const_iterator second_itor;
00309                     for(second_itor = secondary_unit_filter_.begin(); second_itor != secondary_unit_filter_.end(); ++second_itor) {
00310                         if (!unit->matches_filter(vconfig(*second_itor), second_loc)) return MATCH_FAIL;
00311                         result++;
00312                     }
00313 
00314                     break;
00315                 }
00316             }
00317             if(unit == disp.get_const_units().end()) return MATCH_FAIL;
00318         }
00319 
00320     } else if (!unit_filter_.empty()) return MATCH_FAIL;
00321     if(frequency_ && !(rand()%frequency_)) return MATCH_FAIL;
00322 
00323 
00324     if(hits_.empty() == false ) {
00325         if (std::find(hits_.begin(),hits_.end(),hit)== hits_.end()) {
00326             return MATCH_FAIL;
00327         } else {
00328             result ++;
00329         }
00330     }
00331     if(value2_.empty() == false ) {
00332         if (std::find(value2_.begin(),value2_.end(),value2)== value2_.end()) {
00333             return MATCH_FAIL;
00334         } else {
00335             result ++;
00336         }
00337     }
00338     if(!attack) {
00339         if(!primary_attack_filter_.empty())
00340             return MATCH_FAIL;
00341     }
00342     std::vector<config>::const_iterator myitor;
00343     for(myitor = primary_attack_filter_.begin(); myitor != primary_attack_filter_.end(); ++myitor) {
00344         if(!attack->matches_filter(*myitor)) return MATCH_FAIL;
00345         result++;
00346     }
00347     if(!second_attack) {
00348         if(!secondary_attack_filter_.empty())
00349             return MATCH_FAIL;
00350     }
00351     for(myitor = secondary_attack_filter_.begin(); myitor != secondary_attack_filter_.end(); ++myitor) {
00352         if(!second_attack->matches_filter(*myitor)) return MATCH_FAIL;
00353         result++;
00354     }
00355     return result;
00356 
00357 }
00358 
00359 
00360 void unit_animation::fill_initial_animations( std::vector<unit_animation> & animations, const config & cfg)
00361 {
00362     const image::locator default_image = image::locator(cfg["image"]);
00363     std::vector<unit_animation>  animation_base;
00364     std::vector<unit_animation>::const_iterator itor;
00365     add_anims(animations,cfg);
00366     for(itor = animations.begin(); itor != animations.end() ; ++itor) {
00367         if (std::find(itor->event_.begin(),itor->event_.end(),std::string("default"))!= itor->event_.end()) {
00368             animation_base.push_back(*itor);
00369             animation_base.back().base_score_ += unit_animation::DEFAULT_ANIM;
00370             animation_base.back().event_.clear();
00371         }
00372     }
00373 
00374 
00375     if( animation_base.empty() )
00376         animation_base.push_back(unit_animation(0,frame_builder().image(default_image).duration(1),"",unit_animation::DEFAULT_ANIM));
00377 
00378     animations.push_back(unit_animation(0,frame_builder().image(default_image).duration(1),"_disabled_",0));
00379     animations.push_back(unit_animation(0,frame_builder().image(default_image).duration(300).
00380                     blend("0.0~0.3:100,0.3~0.0:200",display::rgb(255,255,255)),"_disabled_selected_",0));
00381     for(itor = animation_base.begin() ; itor != animation_base.end() ; ++itor ) {
00382         //unit_animation tmp_anim = *itor;
00383         // provide all default anims
00384         //no event, providing a catch all anim
00385         //animations.push_back(tmp_anim);
00386 
00387         animations.push_back(*itor);
00388         animations.back().event_ = utils::split("standing");
00389         animations.back().play_offscreen_ = false;
00390 
00391         animations.push_back(*itor);
00392         animations.back().unit_anim_.override(0,animations.back().unit_anim_.get_animation_duration(),"0.9","",0,"","","~GS()");
00393         animations.back().event_ = utils::split("ghosted");
00394 
00395         animations.push_back(*itor);
00396         animations.back().unit_anim_.override(0,1,"0.4","",0,"","","~GS()");
00397         animations.back().event_ = utils::split("disabled_ghosted");
00398 
00399         animations.push_back(*itor);
00400         animations.back().unit_anim_.override(0,300,"","0.0~0.3:100,0.3~0.0:200",display::rgb(255,255,255));
00401         animations.back().event_ = utils::split("selected");
00402 
00403         animations.push_back(*itor);
00404         animations.back().unit_anim_.override(0,600,"0~1:600");
00405         animations.back().event_ = utils::split("recruited");
00406 
00407         animations.push_back(*itor);
00408         animations.back().unit_anim_.override(0,600,"","1~0:600",display::rgb(255,255,255));
00409         animations.back().event_ = utils::split("levelin");
00410 
00411         animations.push_back(*itor);
00412         animations.back().unit_anim_.override(0,600,"","0~1:600,1",display::rgb(255,255,255));
00413         animations.back().event_ = utils::split("levelout");
00414 
00415         animations.push_back(*itor);
00416         animations.back().unit_anim_.override(0,1);
00417         animations.back().event_ = utils::split("pre_movement");
00418 
00419         animations.push_back(*itor);
00420         animations.back().unit_anim_.override(0,1);
00421         animations.back().event_ = utils::split("post_movement");
00422 
00423         animations.push_back(*itor);
00424         animations.back().unit_anim_.override(0,6800,"","",0,"0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,",lexical_cast<std::string>(display::LAYER_UNIT_MOVE_DEFAULT-display::LAYER_UNIT_FIRST));
00425         animations.back().event_ = utils::split("movement");
00426 
00427         animations.push_back(*itor);
00428         animations.back().unit_anim_.override(0,225,"","0.0,0.5:75,0.0:75,0.5:75,0.0",game_display::rgb(255,0,0));
00429         animations.back().hits_.push_back(HIT);
00430         animations.back().hits_.push_back(KILL);
00431         animations.back().event_ = utils::split("defend");
00432 
00433         animations.push_back(*itor);
00434         animations.back().unit_anim_.override(0,1);
00435         animations.back().event_ = utils::split("defend");
00436 
00437         animations.push_back(*itor);
00438         animations.back().unit_anim_.override(-150,300,"","",0,"0~0.6:150,0.6~0:150",lexical_cast<std::string>(display::LAYER_UNIT_MOVE_DEFAULT-display::LAYER_UNIT_FIRST));
00439         animations.back().event_ = utils::split("attack");
00440         animations.back().primary_attack_filter_.push_back(config());
00441         animations.back().primary_attack_filter_.back()["range"] = "melee";
00442 
00443         animations.push_back(*itor);
00444         animations.back().unit_anim_.override(-150,150);
00445         animations.back().event_ = utils::split("attack");
00446         animations.back().primary_attack_filter_.push_back(config());
00447         animations.back().primary_attack_filter_.back()["range"] = "ranged";
00448 
00449         animations.push_back(*itor);
00450         animations.back().unit_anim_.override(0,600,"1~0:600");
00451         animations.back().event_ = utils::split("death");
00452         animations.back().sub_anims_["_death_sound"] = particule();
00453         animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder());
00454         animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder().sound(cfg["die_sound"]),true);
00455 
00456         animations.push_back(*itor);
00457         animations.back().unit_anim_.override(0,1);
00458         animations.back().event_ = utils::split("victory");
00459 
00460         animations.push_back(*itor);
00461         animations.back().unit_anim_.override(0,150,"1~0:150");
00462         animations.back().event_ = utils::split("pre_teleport");
00463 
00464         animations.push_back(*itor);
00465         animations.back().unit_anim_.override(0,150,"0~1:150,1");
00466         animations.back().event_ = utils::split("post_teleport");
00467 
00468         animations.push_back(*itor);
00469         animations.back().unit_anim_.override(0,300,"","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));
00470         animations.back().event_ = utils::split("healed");
00471         animations.back().sub_anims_["_healed_sound"] = particule();
00472         animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder());
00473         animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder().sound("heal.wav"),true);
00474 
00475         animations.push_back(*itor);
00476         animations.back().unit_anim_.override(0,300,"","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));
00477         animations.back().event_ = utils::split("poisoned");
00478         animations.back().sub_anims_["_poison_sound"] = particule();
00479         animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder());
00480         animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound("poison.ogg"),true);
00481 
00482     }
00483 
00484 }
00485 
00486 static void add_simple_anim(std::vector<unit_animation> &animations,
00487     const config &cfg, char const *tag_name, char const *apply_to,
00488     display::tdrawing_layer layer = display::LAYER_UNIT_DEFAULT,
00489     bool offscreen = true)
00490 {
00491     foreach (const animation_branch &ab, prepare_animation(cfg, tag_name))
00492     {
00493         config anim = ab.merge();
00494         anim["apply_to"] = apply_to;
00495         if (!offscreen) {
00496             config::attribute_value &v = anim["offscreen"];
00497             if (v.empty()) v = false;
00498         }
00499         config::attribute_value &v = anim["layer"];
00500         if (v.empty()) v = layer - display::LAYER_UNIT_FIRST;
00501         animations.push_back(unit_animation(anim));
00502     }
00503 }
00504 
00505 void unit_animation::add_anims( std::vector<unit_animation> & animations, const config & cfg)
00506 {
00507     foreach (const animation_branch &ab, prepare_animation(cfg, "animation")) {
00508         animations.push_back(unit_animation(ab.merge()));
00509     }
00510 
00511     int default_layer = display::LAYER_UNIT_DEFAULT - display::LAYER_UNIT_FIRST;
00512     int move_layer = display::LAYER_UNIT_MOVE_DEFAULT - display::LAYER_UNIT_FIRST;
00513     int missile_layer = display::LAYER_UNIT_MISSILE_DEFAULT - display::LAYER_UNIT_FIRST;
00514 
00515     add_simple_anim(animations, cfg, "resistance_anim", "resistance");
00516     add_simple_anim(animations, cfg, "leading_anim", "leading");
00517     add_simple_anim(animations, cfg, "recruit_anim", "recruited");
00518     add_simple_anim(animations, cfg, "recruiting_anim", "recruiting");
00519     add_simple_anim(animations, cfg, "standing_anim", "standing,default", display::LAYER_UNIT_DEFAULT, false);
00520     add_simple_anim(animations, cfg, "idle_anim", "idling", display::LAYER_UNIT_DEFAULT, false);
00521     add_simple_anim(animations, cfg, "levelin_anim", "levelin");
00522     add_simple_anim(animations, cfg, "levelout_anim", "levelout");
00523 
00524     foreach (const animation_branch &ab, prepare_animation(cfg, "healing_anim"))
00525     {
00526         config anim = ab.merge();
00527         anim["apply_to"] = "healing";
00528         if (anim["layer"].empty()) anim["layer"] = default_layer;
00529         anim["value"] = anim["damage"];
00530         animations.push_back(unit_animation(anim));
00531     }
00532 
00533     foreach (const animation_branch &ab, prepare_animation(cfg, "healed_anim"))
00534     {
00535         config anim = ab.merge();
00536         anim["apply_to"] = "healed";
00537         if (anim["layer"].empty()) anim["layer"] = default_layer;
00538         anim["value"] = anim["healing"];
00539         animations.push_back(unit_animation(anim));
00540         animations.back().sub_anims_["_healed_sound"] = particule();
00541         animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder());
00542         animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder().sound("heal.wav"),true);
00543     }
00544 
00545     foreach (const animation_branch &ab, prepare_animation(cfg, "poison_anim"))
00546     {
00547         config anim = ab.merge();
00548         anim["apply_to"] ="poisoned";
00549         if (anim["layer"].empty()) anim["layer"] = default_layer;
00550         anim["value"] = anim["damage"];
00551         animations.push_back(unit_animation(anim));
00552         animations.back().sub_anims_["_poison_sound"] = particule();
00553         animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder());
00554         animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound("poison.ogg"),true);
00555     }
00556 
00557     add_simple_anim(animations, cfg, "pre_movement_anim", "pre_movement", display::LAYER_UNIT_MOVE_DEFAULT);
00558 
00559     foreach (const animation_branch &ab, prepare_animation(cfg, "movement_anim"))
00560     {
00561         config anim = ab.merge();
00562         if (anim["offset"].empty()) {
00563             anim["offset"] = "0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,0~1:200,";
00564         }
00565         anim["apply_to"] = "movement";
00566         if (anim["layer"].empty()) anim["layer"] = move_layer;
00567         animations.push_back(unit_animation(anim));
00568     }
00569 
00570     add_simple_anim(animations, cfg, "post_movement_anim", "post_movement", display::LAYER_UNIT_MOVE_DEFAULT);
00571 
00572     foreach (const animation_branch &ab, prepare_animation(cfg, "defend"))
00573     {
00574         config anim = ab.merge();
00575         anim["apply_to"] = "defend";
00576         if (anim["layer"].empty()) anim["layer"] = default_layer;
00577         if (!anim["damage"].empty() && anim["value"].empty()) {
00578             anim["value"] = anim["damage"];
00579         }
00580         if (anim["hits"].empty())
00581         {
00582             anim["hits"] = false;
00583             animations.push_back(unit_animation(anim));
00584             anim["hits"] = true;
00585             animations.push_back(unit_animation(anim));
00586             animations.back().add_frame(225,frame_builder()
00587                     .image(animations.back().get_last_frame().parameters(0).image)
00588                     .duration(225)
00589                     .blend("0.0,0.5:75,0.0:75,0.5:75,0.0",game_display::rgb(255,0,0)));
00590         }
00591         else
00592         {
00593             std::vector<std::string> v = utils::split(anim["hits"]);
00594             foreach (const std::string &hit_type, v)
00595             {
00596                 config tmp = anim;
00597                 tmp["hits"] = hit_type;
00598                 animations.push_back(unit_animation(tmp));
00599                 if(hit_type == "yes" || hit_type == "hit" || hit_type=="kill") {
00600                     animations.back().add_frame(225,frame_builder()
00601                             .image(animations.back().get_last_frame().parameters(0).image)
00602                             .duration(225)
00603                             .blend("0.0,0.5:75,0.0:75,0.5:75,0.0",game_display::rgb(255,0,0)));
00604                 }
00605             }
00606         }
00607     }
00608 
00609     add_simple_anim(animations, cfg, "draw_weapon_anim", "draw_wepaon", display::LAYER_UNIT_MOVE_DEFAULT);
00610     add_simple_anim(animations, cfg, "sheath_weapon_anim", "sheath_wepaon", display::LAYER_UNIT_MOVE_DEFAULT);
00611 
00612     foreach (const animation_branch &ab, prepare_animation(cfg, "attack_anim"))
00613     {
00614         config anim = ab.merge();
00615         anim["apply_to"] = "attack";
00616         if (anim["layer"].empty()) anim["layer"] = move_layer;
00617         config::const_child_itors missile_fs = anim.child_range("missile_frame");
00618         if (anim["offset"].empty() && missile_fs.first == missile_fs.second) {
00619             anim["offset"] ="0~0.6,0.6~0";
00620         }
00621         if (missile_fs.first != missile_fs.second) {
00622             if (anim["missile_offset"].empty()) anim["missile_offset"] = "0~0.8";
00623             if (anim["missile_layer"].empty()) anim["missile_layer"] = missile_layer;
00624             config tmp;
00625             tmp["duration"] = 1;
00626             anim.add_child("missile_frame", tmp);
00627             anim.add_child_at("missile_frame", tmp, 0);
00628         }
00629 
00630         animations.push_back(unit_animation(anim));
00631     }
00632 
00633     foreach (const animation_branch &ab, prepare_animation(cfg, "death"))
00634     {
00635         config anim = ab.merge();
00636         anim["apply_to"] = "death";
00637         if (anim["layer"].empty()) anim["layer"] = default_layer;
00638         animations.push_back(unit_animation(anim));
00639         image::locator image_loc = animations.back().get_last_frame().parameters(0).image;
00640         animations.back().add_frame(600,frame_builder().image(image_loc).duration(600).highlight("1~0:600"));
00641         if(!cfg["die_sound"].empty()) {
00642             animations.back().sub_anims_["_death_sound"] = particule();
00643             animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder());
00644             animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder().sound(cfg["die_sound"]),true);
00645         }
00646     }
00647 
00648     add_simple_anim(animations, cfg, "victory_anim", "victory");
00649 
00650     foreach (const animation_branch &ab, prepare_animation(cfg, "extra_anim"))
00651     {
00652         config anim = ab.merge();
00653         anim["apply_to"] = anim["flag"];
00654         if (anim["layer"].empty()) anim["layer"] = default_layer;
00655         animations.push_back(unit_animation(anim));
00656     }
00657 
00658     foreach (const animation_branch &ab, prepare_animation(cfg, "teleport_anim"))
00659     {
00660         config anim = ab.merge();
00661         if (anim["layer"].empty()) anim["layer"] = default_layer;
00662         anim["apply_to"] = "pre_teleport";
00663         animations.push_back(unit_animation(anim));
00664         animations.back().unit_anim_.set_end_time(0);
00665         anim["apply_to"] ="post_teleport";
00666         animations.push_back(unit_animation(anim));
00667         animations.back().unit_anim_.remove_frames_until(0);
00668     }
00669 }
00670 
00671 void unit_animation::particule::override(int start_time
00672         , int duration
00673         , const std::string& highlight
00674         , const std::string& blend_ratio
00675         , Uint32 blend_color
00676         , const std::string& offset
00677         , const std::string& layer
00678         , const std::string& modifiers)
00679 {
00680     set_begin_time(start_time);
00681     parameters_.override(duration,highlight,blend_ratio,blend_color,offset,layer,modifiers);
00682 
00683     if(get_animation_duration() < duration) {
00684         const unit_frame & last_frame = get_last_frame();
00685         add_frame(duration -get_animation_duration(), last_frame);
00686     } else if(get_animation_duration() > duration) {
00687         set_end_time(duration);
00688     }
00689 
00690 }
00691 
00692 bool unit_animation::particule::need_update() const
00693 {
00694     if(animated<unit_frame>::need_update()) return true;
00695     if(get_current_frame().need_update()) return true;
00696     if(parameters_.need_update()) return true;
00697     return false;
00698 }
00699 
00700 bool unit_animation::particule::need_minimal_update() const
00701 {
00702     if(get_current_frame_begin_time() != last_frame_begin_time_ ) {
00703         return true;
00704     }
00705     return false;
00706 }
00707 
00708 unit_animation::particule::particule(
00709     const config& cfg, const std::string& frame_string ) :
00710         animated<unit_frame>(),
00711         accelerate(true),
00712         parameters_(),
00713         halo_id_(0),
00714         last_frame_begin_time_(0)
00715 {
00716     config::const_child_itors range = cfg.child_range(frame_string+"frame");
00717     starting_frame_time_=INT_MAX;
00718     if(cfg[frame_string+"start_time"].empty() &&range.first != range.second) {
00719         foreach (const config &frame, range) {
00720             starting_frame_time_ = std::min(starting_frame_time_, frame["begin"].to_int());
00721         }
00722     } else {
00723         starting_frame_time_ = cfg[frame_string+"start_time"];
00724     }
00725 
00726     foreach (const config &frame, range)
00727     {
00728         unit_frame tmp_frame(frame);
00729         add_frame(tmp_frame.duration(),tmp_frame,!tmp_frame.does_not_change());
00730     }
00731     parameters_ = frame_parsed_parameters(frame_builder(cfg,frame_string),get_animation_duration());
00732     if(!parameters_.does_not_change()  ) {
00733             force_change();
00734     }
00735 }
00736 
00737 bool unit_animation::need_update() const
00738 {
00739     if(unit_anim_.need_update()) return true;
00740     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00741     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00742         if(anim_itor->second.need_update()) return true;
00743     }
00744     return false;
00745 }
00746 
00747 bool unit_animation::need_minimal_update() const
00748 {
00749     if(!play_offscreen_) {
00750         return false;
00751     }
00752     if(unit_anim_.need_minimal_update()) return true;
00753     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00754     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00755         if(anim_itor->second.need_minimal_update()) return true;
00756     }
00757     return false;
00758 }
00759 
00760 bool unit_animation::animation_finished() const
00761 {
00762     if(!unit_anim_.animation_finished()) return false;
00763     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00764     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00765         if(!anim_itor->second.animation_finished()) return false;
00766     }
00767     return true;
00768 }
00769 
00770 bool unit_animation::animation_finished_potential() const
00771 {
00772     if(!unit_anim_.animation_finished_potential()) return false;
00773     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00774     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00775         if(!anim_itor->second.animation_finished_potential()) return false;
00776     }
00777     return true;
00778 }
00779 
00780 void unit_animation::update_last_draw_time()
00781 {
00782     double acceleration = unit_anim_.accelerate ? game_display::get_singleton()->turbo_speed() : 1.0;
00783     unit_anim_.update_last_draw_time(acceleration);
00784     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00785     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00786         anim_itor->second.update_last_draw_time(acceleration);
00787     }
00788 }
00789 
00790 int unit_animation::get_end_time() const
00791 {
00792     int result = unit_anim_.get_end_time();
00793     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.end();
00794     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00795         result= std::max<int>(result,anim_itor->second.get_end_time());
00796     }
00797     return result;
00798 }
00799 
00800 int unit_animation::get_begin_time() const
00801 {
00802     int result = unit_anim_.get_begin_time();
00803     std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
00804     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00805         result= std::min<int>(result,anim_itor->second.get_begin_time());
00806     }
00807     return result;
00808 }
00809 
00810 void unit_animation::start_animation(int start_time
00811         , const map_location &src
00812         , const map_location &dst
00813         , bool cycles
00814         , const std::string& text
00815         , const Uint32 text_color
00816         , const bool accelerate)
00817 {
00818     unit_anim_.accelerate = accelerate;
00819     src_ = src;
00820     dst_ = dst;
00821     unit_anim_.start_animation(start_time, cycles);
00822     if(!text.empty()) {
00823         particule crude_build;
00824         crude_build.add_frame(1,frame_builder());
00825         crude_build.add_frame(1,frame_builder().text(text,text_color),true);
00826         sub_anims_["_add_text"] = crude_build;
00827     }
00828     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00829     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00830         anim_itor->second.accelerate = accelerate;
00831         anim_itor->second.start_animation(start_time,cycles);
00832     }
00833 }
00834 
00835 void unit_animation::update_parameters(const map_location &src, const map_location &dst)
00836 {
00837     src_ = src;
00838     dst_ = dst;
00839 }
00840 void unit_animation::pause_animation()
00841 {
00842 
00843     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00844     unit_anim_.pause_animation();
00845     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00846         anim_itor->second.pause_animation();
00847     }
00848 }
00849 void unit_animation::restart_animation()
00850 {
00851 
00852     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00853     unit_anim_.restart_animation();
00854     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00855         anim_itor->second.restart_animation();
00856     }
00857 }
00858 void unit_animation::redraw(frame_parameters& value)
00859 {
00860 
00861     invalidated_=false;
00862     overlaped_hex_.clear();
00863     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00864     value.primary_frame = t_true;
00865     unit_anim_.redraw(value,src_,dst_);
00866     value.primary_frame = t_false;
00867     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00868         anim_itor->second.redraw( value,src_,dst_);
00869     }
00870 }
00871 void unit_animation::clear_haloes()
00872 {
00873 
00874     std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00875     unit_anim_.clear_halo();
00876     for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00877         anim_itor->second.clear_halo();
00878     }
00879 }
00880 bool unit_animation::invalidate(frame_parameters& value)
00881 {
00882     if(invalidated_) return false;
00883     game_display*disp = game_display::get_singleton();
00884     bool complete_redraw =disp->tile_nearly_on_screen(src_) || disp->tile_nearly_on_screen(dst_);
00885     if(overlaped_hex_.empty()) {
00886         if(complete_redraw) {
00887             std::map<std::string,particule>::iterator anim_itor =sub_anims_.begin();
00888             value.primary_frame = t_true;
00889             overlaped_hex_ = unit_anim_.get_overlaped_hex(value,src_,dst_);
00890             value.primary_frame = t_false;
00891             for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
00892                 std::set<map_location> tmp = anim_itor->second.get_overlaped_hex(value,src_,dst_);
00893                 overlaped_hex_.insert(tmp.begin(),tmp.end());
00894             }
00895         } else {
00896             // off screen animations only invalidate their own hex, no propagation,
00897             // but we stil need this to play sounds
00898             overlaped_hex_.insert(src_);
00899         }
00900 
00901     }
00902     if(complete_redraw) {
00903         if( need_update()) {
00904             disp->invalidate(overlaped_hex_);
00905             invalidated_ = true;
00906             return true;
00907         } else {
00908             invalidated_ = disp->propagate_invalidation(overlaped_hex_);
00909             return invalidated_;
00910         }
00911     } else {
00912         if(need_minimal_update()) {
00913             disp->invalidate(overlaped_hex_);
00914             invalidated_ = true;
00915             return true;
00916         } else {
00917             return false;
00918         }
00919     }
00920 }
00921 
00922 
00923 
00924 void unit_animation::particule::redraw(const frame_parameters& value,const map_location &src, const map_location &dst)
00925 {
00926     const unit_frame& current_frame= get_current_frame();
00927     const frame_parameters default_val = parameters_.parameters(get_animation_time() -get_begin_time());
00928     if(get_current_frame_begin_time() != last_frame_begin_time_ ) {
00929         last_frame_begin_time_ = get_current_frame_begin_time();
00930         current_frame.redraw(get_current_frame_time(),true,src,dst,&halo_id_,default_val,value);
00931     } else {
00932         current_frame.redraw(get_current_frame_time(),false,src,dst,&halo_id_,default_val,value);
00933     }
00934 }
00935 void unit_animation::particule::clear_halo()
00936 {
00937     if(halo_id_ != halo::NO_HALO) {
00938         halo::remove(halo_id_);
00939         halo_id_ = halo::NO_HALO;
00940     }
00941 }
00942 std::set<map_location> unit_animation::particule::get_overlaped_hex(const frame_parameters& value,const map_location &src, const map_location &dst)
00943 {
00944     const unit_frame& current_frame= get_current_frame();
00945     const frame_parameters default_val = parameters_.parameters(get_animation_time() -get_begin_time());
00946     return current_frame.get_overlaped_hex(get_current_frame_time(),src,dst,default_val,value);
00947 
00948 }
00949 
00950 unit_animation::particule::~particule()
00951 {
00952     halo::remove(halo_id_);
00953     halo_id_ = halo::NO_HALO;
00954 }
00955 
00956 void unit_animation::particule::start_animation(int start_time, bool cycles)
00957 {
00958     halo::remove(halo_id_);
00959     halo_id_ = halo::NO_HALO;
00960     parameters_.override(get_animation_duration());
00961     animated<unit_frame>::start_animation(start_time,cycles);
00962     last_frame_begin_time_ = get_begin_time() -1;
00963 }
00964 
00965 void unit_animator::add_animation(unit* animated_unit
00966         , const std::string& event
00967         , const map_location &src
00968         , const map_location &dst
00969         , const int value
00970         , bool with_bars
00971         , bool cycles
00972         , const std::string& text
00973         , const Uint32 text_color
00974         , const unit_animation::hit_type hit_type
00975         , const attack_type* attack
00976         , const attack_type* second_attack
00977         , int value2)
00978 {
00979     if(!animated_unit) return;
00980     anim_elem tmp;
00981     game_display*disp = game_display::get_singleton();
00982     tmp.my_unit = animated_unit;
00983     tmp.text = text;
00984     tmp.text_color = text_color;
00985     tmp.src = src;
00986     tmp.with_bars= with_bars;
00987     tmp.cycles = cycles;
00988     tmp.animation = animated_unit->choose_animation(*disp,src,event,dst,value,hit_type,attack,second_attack,value2);
00989     if(!tmp.animation) return;
00990 
00991 
00992 
00993     start_time_ = std::max<int>(start_time_,tmp.animation->get_begin_time());
00994     animated_units_.push_back(tmp);
00995 }
00996 void unit_animator::add_animation(unit* animated_unit
00997         , const unit_animation* anim
00998         , const map_location &src
00999         , bool with_bars
01000         , bool cycles
01001         , const std::string& text
01002         , const Uint32 text_color)
01003 {
01004     if(!animated_unit) return;
01005     anim_elem tmp;
01006     tmp.my_unit = animated_unit;
01007     tmp.text = text;
01008     tmp.text_color = text_color;
01009     tmp.src = src;
01010     tmp.with_bars= with_bars;
01011     tmp.cycles = cycles;
01012     tmp.animation = anim;
01013     if(!tmp.animation) return;
01014 
01015 
01016 
01017     start_time_ = std::max<int>(start_time_,tmp.animation->get_begin_time());
01018     animated_units_.push_back(tmp);
01019 }
01020 void unit_animator::replace_anim_if_invalid(unit* animated_unit
01021         , const std::string& event
01022         , const map_location &src
01023         , const map_location & dst
01024         , const int value
01025         , bool with_bars
01026         , bool cycles
01027         , const std::string& text
01028         , const Uint32 text_color
01029         , const unit_animation::hit_type hit_type
01030         , const attack_type* attack
01031         , const attack_type* second_attack
01032         , int value2)
01033 {
01034     if(!animated_unit) return;
01035     game_display*disp = game_display::get_singleton();
01036     if(animated_unit->get_animation() &&
01037             !animated_unit->get_animation()->animation_finished_potential() &&
01038             animated_unit->get_animation()->matches(*disp,src,dst,animated_unit,event,value,hit_type,attack,second_attack,value2) >unit_animation::MATCH_FAIL) {
01039         anim_elem tmp;
01040         tmp.my_unit = animated_unit;
01041         tmp.text = text;
01042         tmp.text_color = text_color;
01043         tmp.src = src;
01044         tmp.with_bars= with_bars;
01045         tmp.cycles = cycles;
01046         tmp.animation = NULL;
01047         animated_units_.push_back(tmp);
01048     }else {
01049         add_animation(animated_unit,event,src,dst,value,with_bars,cycles,text,text_color,hit_type,attack,second_attack,value2);
01050     }
01051 }
01052 void unit_animator::start_animations()
01053 {
01054     int begin_time = INT_MAX;
01055     std::vector<anim_elem>::iterator anim;
01056     for(anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
01057         if(anim->my_unit->get_animation()) {
01058             if(anim->animation) {
01059                 begin_time = std::min<int>(begin_time,anim->animation->get_begin_time());
01060             } else  {
01061                 begin_time = std::min<int>(begin_time,anim->my_unit->get_animation()->get_begin_time());
01062             }
01063         }
01064     }
01065     for(anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
01066         if(anim->animation) {
01067             anim->my_unit->start_animation(begin_time, anim->animation,
01068                 anim->with_bars, anim->cycles, anim->text, anim->text_color);
01069             anim->animation = NULL;
01070         } else {
01071             anim->my_unit->get_animation()->update_parameters(anim->src,anim->src.get_direction(anim->my_unit->facing()));
01072         }
01073 
01074     }
01075 }
01076 
01077 bool unit_animator::would_end() const
01078 {
01079     bool finished = true;
01080     for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
01081         finished &= anim->my_unit->get_animation()->animation_finished_potential();
01082     }
01083     return finished;
01084 }
01085 void unit_animator::wait_until(int animation_time) const
01086 {
01087     game_display*disp = game_display::get_singleton();
01088     double speed = disp->turbo_speed();
01089     resources::controller->play_slice(false);
01090     int end_tick = animated_units_[0].my_unit->get_animation()->time_to_tick(animation_time);
01091     while (SDL_GetTicks() < static_cast<unsigned int>(end_tick)
01092                 - std::min<int>(static_cast<unsigned int>(20/speed),20)) {
01093 
01094         disp->delay(std::max<int>(0,
01095             std::min<int>(10,
01096             static_cast<int>((animation_time - get_animation_time()) * speed))));
01097         resources::controller->play_slice(false);
01098                 end_tick = animated_units_[0].my_unit->get_animation()->time_to_tick(animation_time);
01099     }
01100     disp->delay(std::max<int>(0,end_tick - SDL_GetTicks() +5));
01101     new_animation_frame();
01102 }
01103 void unit_animator::wait_for_end() const
01104 {
01105     if (game_config::no_delay) return;
01106     bool finished = false;
01107     game_display*disp = game_display::get_singleton();
01108     while(!finished) {
01109         resources::controller->play_slice(false);
01110         disp->delay(10);
01111         finished = true;
01112         for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
01113             finished &= anim->my_unit->get_animation()->animation_finished_potential();
01114         }
01115     }
01116 }
01117 int unit_animator::get_animation_time() const{
01118     return animated_units_[0].my_unit->get_animation()->get_animation_time() ;
01119 }
01120 
01121 int unit_animator::get_animation_time_potential() const{
01122     return animated_units_[0].my_unit->get_animation()->get_animation_time_potential() ;
01123 }
01124 
01125 int unit_animator::get_end_time() const
01126 {
01127         int end_time = INT_MIN;
01128         for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
01129            if(anim->my_unit->get_animation()) {
01130                 end_time = std::max<int>(end_time,anim->my_unit->get_animation()->get_end_time());
01131            }
01132         }
01133         return end_time;
01134 }
01135 void unit_animator::pause_animation()
01136 {
01137         for(std::vector<anim_elem>::iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
01138            if(anim->my_unit->get_animation()) {
01139                 anim->my_unit->get_animation()->pause_animation();
01140            }
01141         }
01142 }
01143 void unit_animator::restart_animation()
01144 {
01145         for(std::vector<anim_elem>::iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
01146            if(anim->my_unit->get_animation()) {
01147                 anim->my_unit->get_animation()->restart_animation();
01148            }
01149         }
01150 }
01151 void unit_animator::set_all_standing()
01152 {
01153         for(std::vector<anim_elem>::iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
01154         anim->my_unit->set_standing();
01155         }
01156 }

Generated by doxygen 1.5.6 on Thu Feb 10 01:01:28 2011 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs