00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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");
00057 }
00058 std::vector<std::string> names;
00059 };
00060 namespace {
00061 tag_name_manager anim_tags;
00062 }
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
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
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
00134
00135
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
00142
00143 ac.branches.clear();
00144 }
00145 }
00146
00147
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
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
00383
00384
00385
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( ; 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( ; 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( ; 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( ; 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( ; 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( ; 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( ; 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( ; 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( ; 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( ; 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( ; 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( ; 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( ; 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
00897
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 }