The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
animation.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2016 by Jeremy Rosen <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13  */
14 
15 #include "global.hpp"
16 
17 #include "units/animation.hpp"
18 
19 #include "filter_context.hpp"
20 #include "game_display.hpp"
21 #include "halo.hpp"
22 #include "map/map.hpp"
23 #include "play_controller.hpp"
24 #include "resources.hpp"
25 #include "units/unit.hpp"
27 #include "units/filter.hpp"
28 #include "variable.hpp"
29 
30 #include <algorithm>
31 
34  names.push_back("animation");
35  names.push_back("attack_anim");
36  names.push_back("death");
37  names.push_back("defend");
38  names.push_back("extra_anim");
39  names.push_back("healed_anim");
40  names.push_back("healing_anim");
41  names.push_back("idle_anim");
42  names.push_back("leading_anim");
43  names.push_back("resistance_anim");
44  names.push_back("levelin_anim");
45  names.push_back("levelout_anim");
46  names.push_back("movement_anim");
47  names.push_back("poison_anim");
48  names.push_back("recruit_anim");
49  names.push_back("recruiting_anim");
50  names.push_back("standing_anim");
51  names.push_back("teleport_anim");
52  names.push_back("pre_movement_anim");
53  names.push_back("post_movement_anim");
54  names.push_back("draw_weapon_anim");
55  names.push_back("sheath_weapon_anim");
56  names.push_back("victory_anim");
57  names.push_back("_transparent"); // Used for WB
58  }
59  std::vector<std::string> names;
60 };
61 namespace {
62  tag_name_manager anim_tags;
63 } //end anonymous namespace
64 
65 const std::vector<std::string>& unit_animation::all_tag_names() {
66  return anim_tags.names;
67 }
68 
70 {
72  : attributes()
73  , children()
74  {
75  }
76 
78  std::vector<config::all_children_iterator> children;
79  config merge() const
80  {
82  for (const config::all_children_iterator &i : children) {
83  result.add_child(i->key, i->cfg);
84  }
85  return result;
86  }
87 };
88 
89 typedef std::list<animation_branch> animation_branches;
90 
92 {
96  animation_cursor(const config &cfg):
97  itors(cfg.all_children_range()), branches(1), parent(nullptr)
98  {
99  branches.back().attributes.merge_attributes(cfg);
100  }
102  itors(cfg.all_children_range()), branches(p->branches), parent(p)
103  {
104  // If similar 'if' condition in parent branches, we need to
105  // cull the branches where there are partial matches.
106  // Hence the need to check if the condition has come up before.
107  // Also, the attributes are merged here between branches.
108  bool previously_hits_set = false;
109  bool previously_direction_set = false;
110  bool previously_terrain_set = false;
111  bool previously_value_set = false;
112  bool previously_value_2nd_set = false;
113  std::string s_cfg_hits = cfg["hits"];
114  std::string s_cfg_direction = cfg["direction"];
115  std::string s_cfg_terrain = cfg["terrain_types"];
116  std::string s_cfg_value = cfg["value"];
117  std::string s_cfg_value_2nd = cfg["value_2nd"];
118  for (std::list<animation_branch>::iterator bi = branches.begin();
119  bi != branches.end(); ++bi)
120  {
121  std::string s_branch_hits = (*bi).attributes["hits"];
122  std::string s_branch_direction = (*bi).attributes["direction"];
123  std::string s_branch_terrain = (*bi).attributes["terrain_types"];
124  std::string s_branch_value = (*bi).attributes["value"];
125  std::string s_branch_value_2nd = (*bi).attributes["value_second"];
126  if (s_branch_hits != "" && s_branch_hits == s_cfg_hits) {
127  previously_hits_set = true;
128  }
129  if (s_branch_direction != "" && s_branch_direction == s_cfg_direction) {
130  previously_direction_set = true;
131  }
132  if (s_branch_terrain != "" && s_branch_terrain == s_cfg_terrain) {
133  previously_terrain_set = true;
134  }
135  if (s_branch_value != "" && s_branch_value == s_cfg_value) {
136  previously_value_set = true;
137  }
138  if (s_branch_value_2nd != "" && s_branch_value_2nd == s_cfg_value_2nd) {
139  previously_value_2nd_set = true;
140  }
141  }
142  // Merge all frames that have new matches and prune any impossible
143  // matches, e.g. hits='yes' and hits='no'
144  for (std::list<animation_branch>::iterator bi = branches.begin();
145  bi != branches.end(); /* nothing */)
146  {
147  std::string s_branch_hits = (*bi).attributes["hits"];
148  std::string s_branch_direction = (*bi).attributes["direction"];
149  std::string s_branch_terrain = (*bi).attributes["terrain_types"];
150  std::string s_branch_value = (*bi).attributes["value"];
151  std::string s_branch_value_2nd = (*bi).attributes["value_second"];
152  bool hits_match = (previously_hits_set && s_branch_hits != s_cfg_hits);
153  bool direction_match = (previously_direction_set && s_branch_direction != s_cfg_direction);
154  bool terrain_match = (previously_terrain_set && s_branch_terrain != s_cfg_terrain);
155  bool value_match = (previously_value_set && s_branch_value != s_cfg_value);
156  bool value_2nd_match = (previously_value_2nd_set && s_branch_value_2nd != s_cfg_value_2nd);
157  if ( (!previously_hits_set || hits_match) &&
158  (!previously_direction_set || direction_match) &&
159  (!previously_terrain_set || terrain_match) &&
160  (!previously_value_set || value_match) &&
161  (!previously_value_2nd_set || value_2nd_match) &&
162  (hits_match || direction_match || terrain_match || value_match || value_2nd_match) )
163  {
164  branches.erase(bi++);
165  }
166  else {
167  (*bi).attributes.merge_attributes(cfg);
168  ++bi;
169  }
170  }
171  // Then we prune all parent branches with similar matches as they
172  // now will not have the full frame list
173  for (std::list<animation_branch>::iterator bi = parent->branches.begin();
174  bi != parent->branches.end(); /* nothing */)
175  {
176  std::string s_branch_hits = (*bi).attributes["hits"];
177  std::string s_branch_direction = (*bi).attributes["direction"];
178  std::string s_branch_terrain = (*bi).attributes["terrain_types"];
179  std::string s_branch_value = (*bi).attributes["value"];
180  std::string s_branch_value_2nd = (*bi).attributes["value_second"];
181  bool hits_match = (previously_hits_set && s_branch_hits == s_cfg_hits);
182  bool direction_match = (previously_direction_set && s_branch_direction == s_cfg_direction);
183  bool terrain_match = (previously_terrain_set && s_branch_terrain == s_cfg_terrain);
184  bool value_match = (previously_value_set && s_branch_value == s_cfg_value);
185  bool value_2nd_match = (previously_value_2nd_set && s_branch_value_2nd == s_cfg_value_2nd);
186  if ( (!previously_hits_set || hits_match) &&
187  (!previously_direction_set || direction_match) &&
188  (!previously_terrain_set || terrain_match) &&
189  (!previously_value_set || value_match) &&
190  (!previously_value_2nd_set || value_2nd_match) &&
191  (hits_match || direction_match || terrain_match || value_match || value_2nd_match) )
192  {
193  parent->branches.erase(bi++);
194  }
195  else ++bi;
196  }
197  }
198 };
199 
200 static void prepare_single_animation(const config &anim_cfg, animation_branches &expanded_anims)
201 {
202  /* The anim_cursor holds the current parsing through the config and the
203  branches hold the data that will be interpreted as the actual animation.
204  The branches store the config attributes for each block and the
205  children of those branches make up all the 'frame', 'missile_frame', etc.
206  individually (so 2 instances of 'frame' would be stored as 2 children) */
207  std::list<animation_cursor> anim_cursors;
208  anim_cursors.push_back(animation_cursor(anim_cfg));
209  while (!anim_cursors.empty())
210  {
211  animation_cursor &ac = anim_cursors.back();
212 
213  // Reached end of sub-tag config block
214  if (ac.itors.first == ac.itors.second) {
215  if (!ac.parent) break;
216  // Merge all the current branches into the parent.
217  ac.parent->branches.splice(ac.parent->branches.end(), ac.branches);
218  anim_cursors.pop_back();
219  continue;
220  }
221  if (ac.itors.first->key != "if") {
222  // Append current config object to all the branches in scope.
223  for (animation_branch &ab : ac.branches) {
224  ab.children.push_back(ac.itors.first);
225  }
226  ++ac.itors.first;
227  continue;
228  }
229  int count = 0;
230  do {
231  /* Copies the current branches to each cursor created for the
232  conditional clauses. Merge attributes of the clause into them. */
233  anim_cursors.push_back(animation_cursor(ac.itors.first->cfg, &ac));
234  ++ac.itors.first;
235  ++count;
236  } while (ac.itors.first != ac.itors.second && ac.itors.first->key == "else");
237  if (count > 1) {
238  // When else statements present, clear all branches before 'if'
239  ac.branches.clear();
240  }
241  }
242 
243  //debug
244  /*for (animation_branch &ab : anim_cursors.back().branches) {
245  std::cout << "--branch--\n" << ab.attributes;
246  for (config::all_children_iterator &ci : ab.children) {
247  std::cout << "--branchcfg--\n" << ci->cfg;
248  }
249  std::cout << "\n";
250  }*/
251 
252  // Create the config object describing each branch.
253  assert(anim_cursors.size() == 1);
254  animation_cursor &ac = anim_cursors.back();
255  expanded_anims.splice(expanded_anims.end(),
256  ac.branches, ac.branches.begin(), ac.branches.end());
257 }
258 
259 static animation_branches prepare_animation(const config &cfg, const std::string &animation_tag)
260 {
261  animation_branches expanded_animations;
262  for (const config &anim : cfg.child_range(animation_tag)) {
263  prepare_single_animation(anim, expanded_animations);
264  }
265  return expanded_animations;
266 }
267 
269  const unit_frame & frame, const std::string& event, const int variation, const frame_builder & builder) :
270  terrain_types_(),
271  unit_filter_(),
272  secondary_unit_filter_(),
273  directions_(),
274  frequency_(0),
275  base_score_(variation),
276  event_(utils::split(event)),
277  value_(),
278  primary_attack_filter_(),
279  secondary_attack_filter_(),
280  hits_(),
281  value2_(),
282  sub_anims_(),
283  unit_anim_(start_time,builder),
284  src_(),
285  dst_(),
286  invalidated_(false),
287  play_offscreen_(true),
288  overlaped_hex_()
289 {
290  add_frame(frame.duration(),frame,!frame.does_not_change());
291 }
292 
293 unit_animation::unit_animation(const config& cfg,const std::string& frame_string ) :
294  terrain_types_(t_translation::read_list(cfg["terrain_type"])),
295  unit_filter_(),
296  secondary_unit_filter_(),
297  directions_(),
298  frequency_(cfg["frequency"]),
299  base_score_(cfg["base_score"]),
300  event_(),
301  value_(),
302  primary_attack_filter_(),
303  secondary_attack_filter_(),
304  hits_(),
305  value2_(),
306  sub_anims_(),
307  unit_anim_(cfg,frame_string),
308  src_(),
309  dst_(),
310  invalidated_(false),
311  play_offscreen_(true),
312  overlaped_hex_()
313 {
314 // if(!cfg["debug"].empty()) printf("DEBUG WML: FINAL\n%s\n\n",cfg.debug().c_str());
315  for (const config::any_child &fr : cfg.all_children_range())
316  {
317  if (fr.key == frame_string) continue;
318  if (fr.key.find("_frame", fr.key.size() - 6) == std::string::npos) continue;
319  if (sub_anims_.find(fr.key) != sub_anims_.end()) continue;
320  sub_anims_[fr.key] = particule(cfg, fr.key.substr(0, fr.key.size() - 5));
321  }
322  event_ =utils::split(cfg["apply_to"]);
323 
324  const std::vector<std::string>& my_directions = utils::split(cfg["direction"]);
325  for(std::vector<std::string>::const_iterator i = my_directions.begin(); i != my_directions.end(); ++i) {
327  directions_.push_back(d);
328  }
329 
330  /*const filter_context * fc = game_display::get_singleton();
331  if (!fc) {
332  fc = resources::filter_con; //!< This is a pointer to the gamestate. Would prefer to tie unit animations only to the display, but for now this is an acceptable fallback. It seems to be relevant because when a second game is created, it seems that the game_display is null at the time that units are being constructed, and hence at the time that this code is running. A different solution might be to delay the team_builder stage 2 call until after the gui is initialized. Note that the current set up could concievably cause problems with the editor, iirc it doesn't initailize a filter context.
333  assert(fc);
334  }*/
335  for (const config &filter : cfg.child_range("filter")) {
336  unit_filter_.push_back(filter);
337  }
338 
339  for (const config &filter : cfg.child_range("filter_second")) {
340  secondary_unit_filter_.push_back(filter);
341  }
342 
343  std::vector<std::string> value_str = utils::split(cfg["value"]);
345  for(value=value_str.begin() ; value != value_str.end() ; ++value) {
346  value_.push_back(atoi(value->c_str()));
347  }
348 
349  std::vector<std::string> hits_str = utils::split(cfg["hits"]);
351  for(hit=hits_str.begin() ; hit != hits_str.end() ; ++hit) {
352  if(*hit == "yes" || *hit == "hit") {
353  hits_.push_back(HIT);
354  }
355  if(*hit == "no" || *hit == "miss") {
356  hits_.push_back(MISS);
357  }
358  if(*hit == "yes" || *hit == "kill" ) {
359  hits_.push_back(KILL);
360  }
361  }
362  std::vector<std::string> value2_str = utils::split(cfg["value_second"]);
364  for(value2=value2_str.begin() ; value2 != value2_str.end() ; ++value2) {
365  value2_.push_back(atoi(value2->c_str()));
366  }
367  for (const config &filter : cfg.child_range("filter_attack")) {
368  primary_attack_filter_.push_back(filter);
369  }
370  for (const config &filter : cfg.child_range("filter_second_attack")) {
371  secondary_attack_filter_.push_back(filter);
372  }
373  play_offscreen_ = cfg["offscreen"].to_bool(true);
374 
375 }
376 
377 int unit_animation::matches(const 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
378 {
379  int result = base_score_;
380  if(!event.empty()&&!event_.empty()) {
381  if (std::find(event_.begin(),event_.end(),event)== event_.end()) {
382  return MATCH_FAIL;
383  } else {
384  result ++;
385  }
386  }
387  if(terrain_types_.empty() == false) {
389  result ++;
390  } else {
391  return MATCH_FAIL;
392  }
393  }
394 
395  if(value_.empty() == false ) {
396  if (std::find(value_.begin(),value_.end(),value)== value_.end()) {
397  return MATCH_FAIL;
398  } else {
399  result ++;
400  }
401  }
402  if(my_unit) {
403  if(directions_.empty()== false) {
404  if (std::find(directions_.begin(),directions_.end(),my_unit->facing())== directions_.end()) {
405  return MATCH_FAIL;
406  } else {
407  result ++;
408  }
409  }
410  std::vector<config>::const_iterator myitor;
411  for(myitor = unit_filter_.begin(); myitor != unit_filter_.end(); ++myitor) {
412  unit_filter f(vconfig(*myitor), &disp);
413  if (!f(*my_unit, loc)) return MATCH_FAIL;
414  ++result;
415  }
416  if(!secondary_unit_filter_.empty()) {
417  unit_map::const_iterator unit = disp.get_units().find(second_loc);
418  if (unit.valid()) {
419  for (const config &c : secondary_unit_filter_) {
420  unit_filter f(vconfig(c), &disp);
421  if (!f(*unit, second_loc)) return MATCH_FAIL;
422  result++;
423  }
424  } else {
425  return MATCH_FAIL;
426  }
427  }
428 
429  } else if (!unit_filter_.empty()) return MATCH_FAIL;
430  if(frequency_ && !(rand()%frequency_)) return MATCH_FAIL;
431 
432 
433  if(hits_.empty() == false ) {
434  if (std::find(hits_.begin(),hits_.end(),hit)== hits_.end()) {
435  return MATCH_FAIL;
436  } else {
437  result ++;
438  }
439  }
440  if(value2_.empty() == false ) {
441  if (std::find(value2_.begin(),value2_.end(),value2)== value2_.end()) {
442  return MATCH_FAIL;
443  } else {
444  result ++;
445  }
446  }
447  if(!attack) {
448  if(!primary_attack_filter_.empty())
449  return MATCH_FAIL;
450  }
451  std::vector<config>::const_iterator myitor;
452  for(myitor = primary_attack_filter_.begin(); myitor != primary_attack_filter_.end(); ++myitor) {
453  if(!attack->matches_filter(*myitor)) return MATCH_FAIL;
454  result++;
455  }
456  if(!second_attack) {
457  if(!secondary_attack_filter_.empty())
458  return MATCH_FAIL;
459  }
460  for(myitor = secondary_attack_filter_.begin(); myitor != secondary_attack_filter_.end(); ++myitor) {
461  if(!second_attack->matches_filter(*myitor)) return MATCH_FAIL;
462  result++;
463  }
464  return result;
465 
466 }
467 
468 
469 void unit_animation::fill_initial_animations( std::vector<unit_animation> & animations, const config & cfg)
470 {
471  const std::string default_image = cfg["image"];
472  std::vector<unit_animation> animation_base;
473  std::vector<unit_animation>::const_iterator itor;
474  add_anims(animations,cfg);
475  for(itor = animations.begin(); itor != animations.end() ; ++itor) {
476  if (std::find(itor->event_.begin(),itor->event_.end(),std::string("default"))!= itor->event_.end()) {
477  animation_base.push_back(*itor);
478  animation_base.back().base_score_ += unit_animation::DEFAULT_ANIM;
479  animation_base.back().event_.clear();
480  }
481  }
482 
483 
484  if( animation_base.empty() )
485  animation_base.push_back(unit_animation(0,frame_builder().image(default_image).duration(1),"",unit_animation::DEFAULT_ANIM));
486 
487  animations.push_back(unit_animation(0,frame_builder().image(default_image).duration(1),"_disabled_",0));
488  animations.push_back(unit_animation(0,frame_builder().image(default_image).duration(300).
489  blend("0.0~0.3:100,0.3~0.0:200",display::rgb(255,255,255)),"_disabled_selected_",0));
490  for(itor = animation_base.begin() ; itor != animation_base.end() ; ++itor ) {
491  //unit_animation tmp_anim = *itor;
492  // provide all default anims
493  //no event, providing a catch all anim
494  //animations.push_back(tmp_anim);
495 
496  animations.push_back(*itor);
497  animations.back().event_ = utils::split("standing");
498  animations.back().play_offscreen_ = false;
499 
500  animations.push_back(*itor);
501  animations.back().event_ = utils::split("ghosted");
502  animations.back().unit_anim_.override(0,animations.back().unit_anim_.get_animation_duration(),particule::UNSET,"0.9","",0,"","","~GS()");
503 
504  animations.push_back(*itor);
505  animations.back().event_ = utils::split("disabled_ghosted");
506  animations.back().unit_anim_.override(0,1,particule::UNSET,"0.4","",0,"","","~GS()");
507 
508  animations.push_back(*itor);
509  animations.back().event_ = utils::split("selected");
510  animations.back().unit_anim_.override(0,300,particule::UNSET,"","0.0~0.3:100,0.3~0.0:200",display::rgb(255,255,255));
511 
512  animations.push_back(*itor);
513  animations.back().event_ = utils::split("recruited");
514  animations.back().unit_anim_.override(0,600,particule::NO_CYCLE,"0~1:600");
515 
516  animations.push_back(*itor);
517  animations.back().event_ = utils::split("levelin");
518  animations.back().unit_anim_.override(0,600,particule::NO_CYCLE,"","1~0:600",display::rgb(255,255,255));
519 
520  animations.push_back(*itor);
521  animations.back().event_ = utils::split("levelout");
522  animations.back().unit_anim_.override(0,600,particule::NO_CYCLE,"","0~1:600,1",display::rgb(255,255,255));
523 
524  animations.push_back(*itor);
525  animations.back().event_ = utils::split("pre_movement");
526  animations.back().unit_anim_.override(0,1,particule::NO_CYCLE);
527 
528  animations.push_back(*itor);
529  animations.back().event_ = utils::split("post_movement");
530  animations.back().unit_anim_.override(0,1,particule::NO_CYCLE);
531 
532  animations.push_back(*itor);
533  animations.back().event_ = utils::split("movement");
534  animations.back().unit_anim_.override(0,200,particule::NO_CYCLE,"","",0,"0~1:200",std::to_string(display::LAYER_UNIT_MOVE_DEFAULT-display::LAYER_UNIT_FIRST));
535 
536  animations.push_back(*itor);
537  animations.back().event_ = utils::split("defend");
538  animations.back().unit_anim_.override(0,animations.back().unit_anim_.get_animation_duration(),particule::NO_CYCLE,"","0.0,0.5:75,0.0:75,0.5:75,0.0",game_display::rgb(255,0,0));
539  animations.back().hits_.push_back(HIT);
540  animations.back().hits_.push_back(KILL);
541 
542  animations.push_back(*itor);
543  animations.back().event_ = utils::split("defend");
544 
545  animations.push_back(*itor);
546  animations.back().event_ = utils::split("attack");
547  animations.back().unit_anim_.override(-150,300,particule::NO_CYCLE,"","",0,"0~0.6:150,0.6~0:150",std::to_string(display::LAYER_UNIT_MOVE_DEFAULT-display::LAYER_UNIT_FIRST));
548  animations.back().primary_attack_filter_.push_back(config());
549  animations.back().primary_attack_filter_.back()["range"] = "melee";
550 
551  animations.push_back(*itor);
552  animations.back().event_ = utils::split("attack");
553  animations.back().unit_anim_.override(-150,150,particule::NO_CYCLE);
554  animations.back().primary_attack_filter_.push_back(config());
555  animations.back().primary_attack_filter_.back()["range"] = "ranged";
556 
557  animations.push_back(*itor);
558  animations.back().event_ = utils::split("death");
559  animations.back().unit_anim_.override(0,600,particule::NO_CYCLE,"1~0:600");
560  animations.back().sub_anims_["_death_sound"] = particule();
561  animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder().sound(cfg["die_sound"]),true);
562 
563  animations.push_back(*itor);
564  animations.back().event_ = utils::split("victory");
565  animations.back().unit_anim_.override(0,animations.back().unit_anim_.get_animation_duration(),particule::CYCLE);
566 
567  animations.push_back(*itor);
568  animations.back().unit_anim_.override(0,150,particule::NO_CYCLE,"1~0:150");
569  animations.back().event_ = utils::split("pre_teleport");
570 
571  animations.push_back(*itor);
572  animations.back().unit_anim_.override(0,150,particule::NO_CYCLE,"0~1:150,1");
573  animations.back().event_ = utils::split("post_teleport");
574 
575  animations.push_back(*itor);
576  animations.back().event_ = utils::split("healing");
577 
578  animations.push_back(*itor);
579  animations.back().event_ = utils::split("healed");
580  animations.back().unit_anim_.override(0,300,particule::NO_CYCLE,"","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));
581  std::string healed_sound;
582  if (cfg["healed_sound"].empty()) {
583  healed_sound = "heal.wav";
584  } else {
585  healed_sound = cfg["healed_sound"].str();
586  }
587  animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder().sound(healed_sound),true);
588 
589  animations.push_back(*itor);
590  animations.back().event_ = utils::split("poisoned");
591  animations.back().unit_anim_.override(0,300,particule::NO_CYCLE,"","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));
592  animations.back().sub_anims_["_poison_sound"] = particule();
593  animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound(game_config::sounds::status::poisoned),true);
594 
595  }
596 
597 }
598 
599 static void add_simple_anim(std::vector<unit_animation> &animations,
600  const config &cfg, char const *tag_name, char const *apply_to,
602  bool offscreen = true)
603 {
604  for (const animation_branch &ab : prepare_animation(cfg, tag_name))
605  {
606  config anim = ab.merge();
607  anim["apply_to"] = apply_to;
608  if (!offscreen) {
609  config::attribute_value &v = anim["offscreen"];
610  if (v.empty()) v = false;
611  }
612  config::attribute_value &v = anim["layer"];
613  if (v.empty()) v = layer - display::LAYER_UNIT_FIRST;
614  animations.push_back(unit_animation(anim));
615  }
616 }
617 
618 void unit_animation::add_anims( std::vector<unit_animation> & animations, const config & cfg)
619 {
620  for (const animation_branch &ab : prepare_animation(cfg, "animation")) {
621  animations.push_back(unit_animation(ab.merge()));
622  }
623 
624  const int default_layer = display::LAYER_UNIT_DEFAULT - display::LAYER_UNIT_FIRST;
627 
628  add_simple_anim(animations, cfg, "resistance_anim", "resistance");
629  add_simple_anim(animations, cfg, "leading_anim", "leading");
630  add_simple_anim(animations, cfg, "recruit_anim", "recruited");
631  add_simple_anim(animations, cfg, "recruiting_anim", "recruiting");
632  add_simple_anim(animations, cfg, "idle_anim", "idling", display::LAYER_UNIT_DEFAULT, false);
633  add_simple_anim(animations, cfg, "levelin_anim", "levelin");
634  add_simple_anim(animations, cfg, "levelout_anim", "levelout");
635 
636  for (const animation_branch &ab : prepare_animation(cfg, "standing_anim"))
637  {
638  config anim = ab.merge();
639  anim["apply_to"] = "standing";
640  anim["cycles"] = "true";
641  // add cycles to all frames within a standing animation block
642  for (config::all_children_iterator ci : ab.children)
643  {
644  std::string sub_frame_name = ci->key;
645  size_t pos = sub_frame_name.find("_frame");
646  if (pos != std::string::npos) {
647  anim[sub_frame_name.substr(0,pos)+"_cycles"] = "true";
648  }
649  }
650  if (anim["layer"].empty()) anim["layer"] = default_layer;
651  if (anim["offscreen"].empty()) anim["offscreen"] = false;
652  animations.push_back(unit_animation(anim));
653  }
654  // standing animations are also used as default animations
655  for (const animation_branch &ab : prepare_animation(cfg, "standing_anim"))
656  {
657  config anim = ab.merge();
658  anim["apply_to"] = "default";
659  anim["cycles"] = "true";
660  for (config::all_children_iterator ci : ab.children)
661  {
662  std::string sub_frame_name = ci->key;
663  size_t pos = sub_frame_name.find("_frame");
664  if (pos != std::string::npos) {
665  anim[sub_frame_name.substr(0,pos)+"_cycles"] = "true";
666  }
667  }
668  if (anim["layer"].empty()) anim["layer"] = default_layer;
669  if (anim["offscreen"].empty()) anim["offscreen"] = false;
670  animations.push_back(unit_animation(anim));
671  }
672  for (const animation_branch &ab : prepare_animation(cfg, "healing_anim"))
673  {
674  config anim = ab.merge();
675  anim["apply_to"] = "healing";
676  if (anim["layer"].empty()) anim["layer"] = default_layer;
677  anim["value"] = anim["damage"];
678  animations.push_back(unit_animation(anim));
679  }
680 
681  for (const animation_branch &ab : prepare_animation(cfg, "healed_anim"))
682  {
683  config anim = ab.merge();
684  anim["apply_to"] = "healed";
685  if (anim["layer"].empty()) anim["layer"] = default_layer;
686  anim["value"] = anim["healing"];
687  animations.push_back(unit_animation(anim));
688  animations.back().sub_anims_["_healed_sound"] = particule();
689  std::string healed_sound;
690  if (cfg["healed_sound"].empty()) {
691  healed_sound = "heal.wav";
692  } else {
693  healed_sound = cfg["healed_sound"].str();
694  }
695  animations.back().sub_anims_["_healed_sound"].add_frame(1,frame_builder().sound(healed_sound),true);
696  }
697 
698  for (const animation_branch &ab : prepare_animation(cfg, "poison_anim"))
699  {
700  config anim = ab.merge();
701  anim["apply_to"] ="poisoned";
702  if (anim["layer"].empty()) anim["layer"] = default_layer;
703  anim["value"] = anim["damage"];
704  animations.push_back(unit_animation(anim));
705  animations.back().sub_anims_["_poison_sound"] = particule();
706  animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound(game_config::sounds::status::poisoned),true);
707  }
708 
709  add_simple_anim(animations, cfg, "pre_movement_anim", "pre_movement", display::LAYER_UNIT_MOVE_DEFAULT);
710 
711  for (const animation_branch &ab : prepare_animation(cfg, "movement_anim"))
712  {
713  config anim = ab.merge();
714  if (anim["offset"].empty()) {
715  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,";
716  }
717  anim["apply_to"] = "movement";
718  if (anim["layer"].empty()) anim["layer"] = move_layer;
719  animations.push_back(unit_animation(anim));
720  }
721 
722  add_simple_anim(animations, cfg, "post_movement_anim", "post_movement", display::LAYER_UNIT_MOVE_DEFAULT);
723 
724  for (const animation_branch &ab : prepare_animation(cfg, "defend"))
725  {
726  config anim = ab.merge();
727  anim["apply_to"] = "defend";
728  if (anim["layer"].empty()) anim["layer"] = default_layer;
729  if (!anim["damage"].empty() && anim["value"].empty()) {
730  anim["value"] = anim["damage"];
731  }
732  if (anim["hits"].empty())
733  {
734  anim["hits"] = false;
735  animations.push_back(unit_animation(anim));
736  animations.back().base_score_--; //so default doesn't interefere with 'if' block
737  anim["hits"] = true;
738  animations.push_back(unit_animation(anim));
739  animations.back().base_score_--;
740  image::locator image_loc = animations.back().get_last_frame().end_parameters().image;
741  animations.back().add_frame(225,frame_builder()
742  .image(image_loc.get_filename()+image_loc.get_modifications())
743  .duration(225)
744  .blend("0.0,0.5:75,0.0:75,0.5:75,0.0",game_display::rgb(255,0,0)));
745  }
746  else
747  {
748  std::vector<std::string> v = utils::split(anim["hits"]);
749  for (const std::string &hit_type : v)
750  {
751  config tmp = anim;
752  tmp["hits"] = hit_type;
753  animations.push_back(unit_animation(tmp));
754  image::locator image_loc = animations.back().get_last_frame().end_parameters().image;
755  if(hit_type == "yes" || hit_type == "hit" || hit_type=="kill") {
756  animations.back().add_frame(225,frame_builder()
757  .image(image_loc.get_filename()+image_loc.get_modifications())
758  .duration(225)
759  .blend("0.0,0.5:75,0.0:75,0.5:75,0.0",game_display::rgb(255,0,0)));
760  }
761  }
762  }
763  }
764 
765  add_simple_anim(animations, cfg, "draw_weapon_anim", "draw_weapon", display::LAYER_UNIT_MOVE_DEFAULT);
766  add_simple_anim(animations, cfg, "sheath_weapon_anim", "sheath_weapon", display::LAYER_UNIT_MOVE_DEFAULT);
767 
768  for (const animation_branch &ab : prepare_animation(cfg, "attack_anim"))
769  {
770  config anim = ab.merge();
771  anim["apply_to"] = "attack";
772  if (anim["layer"].empty()) anim["layer"] = move_layer;
773  config::const_child_itors missile_fs = anim.child_range("missile_frame");
774  if (anim["offset"].empty() && missile_fs.first == missile_fs.second) {
775  anim["offset"] ="0~0.6,0.6~0";
776  }
777  if (missile_fs.first != missile_fs.second) {
778  if (anim["missile_offset"].empty()) anim["missile_offset"] = "0~0.8";
779  if (anim["missile_layer"].empty()) anim["missile_layer"] = missile_layer;
780  config tmp;
781  tmp["duration"] = 1;
782  anim.add_child("missile_frame", tmp);
783  anim.add_child_at("missile_frame", tmp, 0);
784  }
785 
786  animations.push_back(unit_animation(anim));
787  }
788 
789  for (const animation_branch &ab : prepare_animation(cfg, "death"))
790  {
791  config anim = ab.merge();
792  anim["apply_to"] = "death";
793  if (anim["layer"].empty()) anim["layer"] = default_layer;
794  animations.push_back(unit_animation(anim));
795  image::locator image_loc = animations.back().get_last_frame().end_parameters().image;
796 
797  animations.back().add_frame(600,frame_builder()
798  .image(image_loc.get_filename()+image_loc.get_modifications())
799  .duration(600)
800  .highlight("1~0:600"));
801  if(!cfg["die_sound"].empty()) {
802  animations.back().sub_anims_["_death_sound"] = particule();
803  animations.back().sub_anims_["_death_sound"].add_frame(1,frame_builder().sound(cfg["die_sound"]),true);
804  }
805  }
806 
807  add_simple_anim(animations, cfg, "victory_anim", "victory");
808 
809  for (const animation_branch &ab : prepare_animation(cfg, "extra_anim"))
810  {
811  config anim = ab.merge();
812  anim["apply_to"] = anim["flag"];
813  if (anim["layer"].empty()) anim["layer"] = default_layer;
814  animations.push_back(unit_animation(anim));
815  }
816 
817  for (const animation_branch &ab : prepare_animation(cfg, "teleport_anim"))
818  {
819  config anim = ab.merge();
820  if (anim["layer"].empty()) anim["layer"] = default_layer;
821  anim["apply_to"] = "pre_teleport";
822  animations.push_back(unit_animation(anim));
823  animations.back().unit_anim_.set_end_time(0);
824  anim["apply_to"] ="post_teleport";
825  animations.push_back(unit_animation(anim));
826  animations.back().unit_anim_.remove_frames_until(0);
827  }
828 }
829 
831  , int duration
832  , const cycle_state cycles
833  , const std::string& highlight
834  , const std::string& blend_ratio
835  , Uint32 blend_color
836  , const std::string& offset
837  , const std::string& layer
838  , const std::string& modifiers)
839 {
840  set_begin_time(start_time);
841  parameters_.override(duration,highlight,blend_ratio,blend_color,offset,layer,modifiers);
842 
843  if(cycles == CYCLE) {
844  cycles_=true;
845 
846  } else if(cycles==NO_CYCLE) {
847  cycles_=false;
848  }else {
849  //nothing
850  }
851  if(get_animation_duration() < duration) {
852  const unit_frame & last_frame = get_last_frame();
853  add_frame(duration -get_animation_duration(), last_frame);
854  } else if(get_animation_duration() > duration) {
855  set_end_time(duration);
856  }
857 
858 }
859 
861 {
862  if(animated<unit_frame>::need_update()) return true;
863  if(get_current_frame().need_update()) return true;
864  if(parameters_.need_update()) return true;
865  return false;
866 }
867 
869 {
870  if(get_current_frame_begin_time() != last_frame_begin_time_ ) {
871  return true;
872  }
873  return false;
874 }
875 
877  const config& cfg, const std::string& frame_string ) :
878  animated<unit_frame>(),
879  accelerate(true),
880  parameters_(),
881  halo_id_(),
882  last_frame_begin_time_(0),
883  cycles_(false)
884 {
885  config::const_child_itors range = cfg.child_range(frame_string+"frame");
886  starting_frame_time_=INT_MAX;
887  if(cfg[frame_string+"start_time"].empty() &&range.first != range.second) {
888  for (const config &frame : range) {
889  starting_frame_time_ = std::min(starting_frame_time_, frame["begin"].to_int());
890  }
891  } else {
892  starting_frame_time_ = cfg[frame_string+"start_time"];
893  }
894 
895  for (const config &frame : range)
896  {
897  unit_frame tmp_frame(frame);
898  add_frame(tmp_frame.duration(),tmp_frame,!tmp_frame.does_not_change());
899  }
900  cycles_ = cfg[frame_string+"cycles"].to_bool(false);
902  if(!parameters_.does_not_change() ) {
903  force_change();
904  }
905 }
906 
908 {
909  if(unit_anim_.need_update()) return true;
910  std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
911  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
912  if(anim_itor->second.need_update()) return true;
913  }
914  return false;
915 }
916 
918 {
919  if(!play_offscreen_) {
920  return false;
921  }
922  if(unit_anim_.need_minimal_update()) return true;
923  std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
924  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
925  if(anim_itor->second.need_minimal_update()) return true;
926  }
927  return false;
928 }
929 
931 {
932  if(!unit_anim_.animation_finished()) return false;
933  std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
934  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
935  if(!anim_itor->second.animation_finished()) return false;
936  }
937  return true;
938 }
939 
941 {
942  if(!unit_anim_.animation_finished_potential()) return false;
943  std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
944  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
945  if(!anim_itor->second.animation_finished_potential()) return false;
946  }
947  return true;
948 }
949 
951 {
952  double acceleration = unit_anim_.accelerate ? game_display::get_singleton()->turbo_speed() : 1.0;
953  unit_anim_.update_last_draw_time(acceleration);
955  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
956  anim_itor->second.update_last_draw_time(acceleration);
957  }
958 }
959 
961 {
963  std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
964  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
965  result= std::max<int>(result,anim_itor->second.get_end_time());
966  }
967  return result;
968 }
969 
971 {
973  std::map<std::string,particule>::const_iterator anim_itor =sub_anims_.begin();
974  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
975  result= std::min<int>(result,anim_itor->second.get_begin_time());
976  }
977  return result;
978 }
979 
981  , const map_location &src
982  , const map_location &dst
983  , const std::string& text
984  , const Uint32 text_color
985  , const bool accelerate)
986 {
987  unit_anim_.accelerate = accelerate;
988  src_ = src;
989  dst_ = dst;
990  unit_anim_.start_animation(start_time);
991  if(!text.empty()) {
992  particule crude_build;
993  crude_build.add_frame(1,frame_builder());
994  crude_build.add_frame(1,frame_builder().text(text,text_color),true);
995  sub_anims_["_add_text"] = crude_build;
996  }
998  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
999  anim_itor->second.accelerate = accelerate;
1000  anim_itor->second.start_animation(start_time);
1001  }
1002 }
1003 
1005 {
1006  src_ = src;
1007  dst_ = dst;
1008 }
1010 {
1011 
1014  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
1015  anim_itor->second.pause_animation();
1016  }
1017 }
1019 {
1020 
1023  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
1024  anim_itor->second.restart_animation();
1025  }
1026 }
1028 {
1029 
1030  invalidated_=false;
1031  overlaped_hex_.clear();
1033  value.primary_frame = t_true;
1034  unit_anim_.redraw(value,src_,dst_, halo_man);
1035  value.primary_frame = t_false;
1036  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
1037  anim_itor->second.redraw( value,src_,dst_, halo_man);
1038  }
1039 }
1041 {
1042 
1045  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
1046  anim_itor->second.clear_halo();
1047  }
1048 }
1050 {
1051  if(invalidated_) return false;
1053  bool complete_redraw =disp->tile_nearly_on_screen(src_) || disp->tile_nearly_on_screen(dst_);
1054  if(overlaped_hex_.empty()) {
1055  if(complete_redraw) {
1057  value.primary_frame = t_true;
1059  value.primary_frame = t_false;
1060  for( /*null*/; anim_itor != sub_anims_.end() ; ++anim_itor) {
1061  std::set<map_location> tmp = anim_itor->second.get_overlaped_hex(value,src_,dst_);
1062  overlaped_hex_.insert(tmp.begin(),tmp.end());
1063  }
1064  } else {
1065  // off screen animations only invalidate their own hex, no propagation,
1066  // but we still need this to play sounds
1067  overlaped_hex_.insert(src_);
1068  }
1069 
1070  }
1071  if(complete_redraw) {
1072  if( need_update()) {
1073  disp->invalidate(overlaped_hex_);
1074  invalidated_ = true;
1075  return true;
1076  } else {
1078  return invalidated_;
1079  }
1080  } else {
1081  if(need_minimal_update()) {
1082  disp->invalidate(overlaped_hex_);
1083  invalidated_ = true;
1084  return true;
1085  } else {
1086  return false;
1087  }
1088  }
1089 }
1090 
1092 {
1093  std::ostringstream outstream;
1094  outstream << *this;
1095  return outstream.str();
1096 }
1097 
1098 std::ostream& operator << (std::ostream& outstream, const unit_animation& u_animation)
1099 {
1100  std::cout << "[";
1101  int i=0;
1102  for (std::string event : u_animation.event_) {
1103  if (i>0) std::cout << ','; i++;
1104  std::cout << event;
1105  }
1106  std::cout << "]\n";
1107 
1108  std::cout << "\tstart_time=" << u_animation.get_begin_time() << '\n';
1109 
1110  if (u_animation.hits_.size() > 0) {
1111  std::cout << "\thits=";
1112  i=0;
1113  for (const unit_animation::hit_type hit_type : u_animation.hits_) {
1114  if (i>0) std::cout << ','; i++;
1115  switch (hit_type) {
1116  case (unit_animation::HIT) : std::cout << "hit"; break;
1117  case (unit_animation::MISS) : std::cout << "miss"; break;
1118  case (unit_animation::KILL) : std::cout << "kill"; break;
1119  case (unit_animation::INVALID) : std::cout << "invalid"; break;
1120  }
1121  }
1122  std::cout << '\n';
1123  }
1124  if (u_animation.directions_.size() > 0) {
1125  std::cout << "\tdirections=";
1126  i=0;
1127  for (const map_location::DIRECTION direction : u_animation.directions_) {
1128  if (i>0) std::cout << ','; i++;
1129  switch (direction) {
1130  case (map_location::NORTH) : std::cout << "n"; break;
1131  case (map_location::NORTH_EAST): std::cout << "ne"; break;
1132  case (map_location::SOUTH_EAST): std::cout << "se"; break;
1133  case (map_location::SOUTH) : std::cout << "s"; break;
1134  case (map_location::SOUTH_WEST): std::cout << "sw"; break;
1135  case (map_location::NORTH_WEST): std::cout << "nw"; break;
1136  default: break;
1137  }
1138  }
1139  std::cout << '\n';
1140  }
1141  if (u_animation.terrain_types_.size() > 0) {
1142  i=0;
1143  std::cout << "\tterrain=";
1144  for (const t_translation::t_terrain terrain : u_animation.terrain_types_) {
1145  if (i>0) std::cout << ','; i++;
1146  std::cout << terrain;
1147  }
1148  std::cout << '\n';
1149  }
1150  if (u_animation.frequency_>0) std::cout << "frequency=" << u_animation.frequency_ << '\n';
1151 
1152  if (u_animation.unit_filter_.size() > 0) {
1153  std::cout << "[filter]\n";
1154  for (const config & cfg : u_animation.unit_filter_) {
1155  std::cout << cfg.debug();
1156  }
1157  //std::cout << "TODO: create debugging output for unit filters";
1158  std::cout << "[/filter]\n";
1159  }
1160  if (u_animation.secondary_unit_filter_.size() > 0) {
1161  std::cout << "[filter_second]\n";
1162  for (const config & cfg : u_animation.secondary_unit_filter_) {
1163  std::cout << cfg.debug();
1164  }
1165  //std::cout << "TODO: create debugging output for unit filters";
1166  std::cout << "[/filter_second]\n";
1167  }
1168  if (u_animation.primary_attack_filter_.size() > 0) {
1169  std::cout << "[filter_attack]\n";
1170  for (const config cfg : u_animation.primary_attack_filter_) {
1171  std::cout << cfg.debug();
1172  }
1173  std::cout << "[/filter_attack]\n";
1174  }
1175  if (u_animation.secondary_attack_filter_.size() > 0) {
1176  std::cout << "[filter_second_attack]\n";
1177  for (const config cfg : u_animation.secondary_attack_filter_) {
1178  std::cout << cfg.debug();
1179  }
1180  std::cout << "[/filter_second_attack]\n";
1181  }
1182 
1183  for (size_t i=0; i<u_animation.unit_anim_.get_frames_count(); i++) {
1184  std::cout << "\t[frame]\n";
1185  for (const std::string frame_string : u_animation.unit_anim_.get_frame(i).debug_strings()) {
1186  std::cout << "\t\t" << frame_string <<"\n";
1187  }
1188  std::cout << "\t[/frame]\n";
1189  }
1190 
1191  for (std::pair<std::string, unit_animation::particule> p : u_animation.sub_anims_) {
1192  for (size_t i=0; i<p.second.get_frames_count(); i++) {
1193  std::string sub_frame_name = p.first;
1194  size_t pos = sub_frame_name.find("_frame");
1195  if (pos != std::string::npos) sub_frame_name = sub_frame_name.substr(0,pos);
1196  std::cout << "\t" << sub_frame_name << "_start_time=" << p.second.get_begin_time() << '\n';
1197  std::cout << "\t[" << p.first << "]\n";
1198  for (const std::string frame_string : p.second.get_frame(i).debug_strings()) {
1199  std::cout << "\t\t" << frame_string << '\n';
1200  }
1201  std::cout << "\t[/" << p.first << "]\n";
1202  }
1203  }
1204 
1205  std::cout << "[/";
1206  i=0;
1207  for (std::string event : u_animation.event_) {
1208  if (i>0) std::cout << ','; i++;
1209  std::cout << event;
1210  }
1211  std::cout << "]\n";
1212  return outstream;
1213 }
1214 
1215 
1217 {
1218  const unit_frame& current_frame= get_current_frame();
1219  const int animation_time = get_animation_time();
1220  const frame_parameters default_val = parameters_.parameters(animation_time -get_begin_time());
1221 
1222  // everything is relative to the first frame in an attack/defense/etc. block.
1223  // so we need to check if this particular frame is due to be shown at this time
1224  bool in_scope_of_frame = (animation_time >= get_current_frame_begin_time() ? true: false);
1225  if (animation_time > get_current_frame_end_time()) in_scope_of_frame = false;
1226 
1227  // sometimes even if the frame is not due to be shown, a frame image still must be shown.
1228  // i.e. in a defense animation that is shorter than an attack animation.
1229  // the halos should not persist though and use the 'in_scope_of_frame' variable.
1230 
1231  // for sound frames we want the first time variable set only after the frame has started.
1232  if(get_current_frame_begin_time() != last_frame_begin_time_ && animation_time >= get_current_frame_begin_time()) {
1233  last_frame_begin_time_ = get_current_frame_begin_time();
1234  current_frame.redraw(get_current_frame_time(),true,in_scope_of_frame,src,dst,halo_id_,halo_man,default_val,value);
1235  } else {
1236  current_frame.redraw(get_current_frame_time(),false,in_scope_of_frame,src,dst,halo_id_,halo_man,default_val,value);
1237  }
1238 }
1240 {
1241  halo_id_ = halo::handle(); // halo::NO_HALO
1242 }
1244 {
1245  const unit_frame& current_frame= get_current_frame();
1246  const frame_parameters default_val = parameters_.parameters(get_animation_time() -get_begin_time());
1247  return current_frame.get_overlaped_hex(get_current_frame_time(),src,dst,default_val,value);
1248 
1249 }
1250 
1252 {
1253  halo_id_ = halo::handle(); // halo::NO_HALO
1254 }
1255 
1257 {
1258  halo_id_ = halo::handle(); // halo::NO_HALO
1259  parameters_.override(get_animation_duration());
1260  animated<unit_frame>::start_animation(start_time,cycles_);
1261  last_frame_begin_time_ = get_begin_time() -1;
1262 }
1263 
1264 
1265 
1266 void unit_animator::add_animation(const unit* animated_unit
1267  , const std::string& event
1268  , const map_location &src
1269  , const map_location &dst
1270  , const int value
1271  , bool with_bars
1272  , const std::string& text
1273  , const Uint32 text_color
1275  , const attack_type* attack
1276  , const attack_type* second_attack
1277  , int value2)
1278 {
1279  if(!animated_unit) return;
1280  anim_elem tmp;
1282  tmp.my_unit = unit_const_ptr(animated_unit);
1283  tmp.text = text;
1284  tmp.text_color = text_color;
1285  tmp.src = src;
1286  tmp.with_bars= with_bars;
1287  tmp.animation = animated_unit->anim_comp().choose_animation(*disp,src,event,dst,value,hit_type,attack,second_attack,value2);
1288  if(!tmp.animation) return;
1289 
1290  start_time_ = std::max<int>(start_time_,tmp.animation->get_begin_time());
1291  animated_units_.push_back(tmp);
1292 }
1293 
1294 void unit_animator::add_animation(const unit* animated_unit
1295  , const unit_animation* anim
1296  , const map_location &src
1297  , bool with_bars
1298  , const std::string& text
1299  , const Uint32 text_color)
1300 {
1301  if(!animated_unit) return;
1302  anim_elem tmp;
1303  tmp.my_unit = unit_const_ptr(animated_unit);
1304  tmp.text = text;
1305  tmp.text_color = text_color;
1306  tmp.src = src;
1307  tmp.with_bars= with_bars;
1308  tmp.animation = anim;
1309  if(!tmp.animation) return;
1310 
1311  start_time_ = std::max<int>(start_time_,tmp.animation->get_begin_time());
1312  animated_units_.push_back(tmp);
1313 }
1314 
1316  , const std::string& event
1317  , const map_location &src
1318  , const map_location & dst
1319  , const int value
1320  , bool with_bars
1321  , const std::string& text
1322  , const Uint32 text_color
1324  , const attack_type* attack
1325  , const attack_type* second_attack
1326  , int value2)
1327 {
1328  if(!animated_unit) return;
1330  if(animated_unit->anim_comp().get_animation() &&
1331  !animated_unit->anim_comp().get_animation()->animation_finished_potential() &&
1332  animated_unit->anim_comp().get_animation()->matches(*disp,src,dst,animated_unit,event,value,hit_type,attack,second_attack,value2) >unit_animation::MATCH_FAIL) {
1333  anim_elem tmp;
1334  tmp.my_unit = unit_const_ptr(animated_unit);
1335  tmp.text = text;
1336  tmp.text_color = text_color;
1337  tmp.src = src;
1338  tmp.with_bars= with_bars;
1339  tmp.animation = nullptr;
1340  animated_units_.push_back(tmp);
1341  }else {
1342  add_animation(animated_unit,event,src,dst,value,with_bars,text,text_color,hit_type,attack,second_attack,value2);
1343  }
1344 }
1345 
1347 {
1348  int begin_time = INT_MAX;
1350  for(anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
1351  if(anim->my_unit->anim_comp().get_animation()) {
1352  if(anim->animation) {
1353  begin_time = std::min<int>(begin_time,anim->animation->get_begin_time());
1354  } else {
1355  begin_time = std::min<int>(begin_time,anim->my_unit->anim_comp().get_animation()->get_begin_time());
1356  }
1357  }
1358  }
1359  for(anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
1360  if(anim->animation) {
1361  anim->my_unit->anim_comp().start_animation(begin_time, anim->animation,
1362  anim->with_bars, anim->text, anim->text_color);
1363  anim->animation = nullptr;
1364  } else {
1365  anim->my_unit->anim_comp().get_animation()->update_parameters(anim->src,anim->src.get_direction(anim->my_unit->facing()));
1366  }
1367 
1368  }
1369 }
1370 
1372 {
1373  bool finished = true;
1374  for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
1375  finished &= anim->my_unit->anim_comp().get_animation()->animation_finished_potential();
1376  }
1377  return finished;
1378 }
1379 
1380 void unit_animator::wait_until(int animation_time) const
1381 {
1383  double speed = disp->turbo_speed();
1385  int end_tick = animated_units_[0].my_unit->anim_comp().get_animation()->time_to_tick(animation_time);
1386  while (SDL_GetTicks() < static_cast<unsigned int>(end_tick)
1387  - std::min<int>(static_cast<unsigned int>(20/speed),20)) {
1388 
1389  CVideo::delay(std::max<int>(0,
1390  std::min<int>(10,
1391  static_cast<int>((animation_time - get_animation_time()) * speed))));
1393  end_tick = animated_units_[0].my_unit->anim_comp().get_animation()->time_to_tick(animation_time);
1394  }
1395  CVideo::delay(std::max<int>(0,end_tick - SDL_GetTicks() +5));
1397 }
1398 
1400 {
1401  if (game_config::no_delay) return;
1402 
1403  bool finished = false;
1404 
1405  while(!finished) {
1407 
1408  CVideo::delay(10);
1409  finished = true;
1410  for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
1411  finished &= anim->my_unit->anim_comp().get_animation()->animation_finished_potential();
1412  }
1413  }
1414 }
1415 
1417  return animated_units_[0].my_unit->anim_comp().get_animation()->get_animation_time() ;
1418 }
1419 
1421  return animated_units_[0].my_unit->anim_comp().get_animation()->get_animation_time_potential() ;
1422 }
1423 
1425 {
1426  int end_time = INT_MIN;
1427  for(std::vector<anim_elem>::const_iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
1428  if(anim->my_unit->anim_comp().get_animation()) {
1429  end_time = std::max<int>(end_time,anim->my_unit->anim_comp().get_animation()->get_end_time());
1430  }
1431  }
1432  return end_time;
1433 }
1434 
1436 {
1437  for(std::vector<anim_elem>::iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
1438  if(anim->my_unit->anim_comp().get_animation()) {
1439  anim->my_unit->anim_comp().get_animation()->pause_animation();
1440  }
1441  }
1442 }
1443 
1445 {
1446  for(std::vector<anim_elem>::iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
1447  if(anim->my_unit->anim_comp().get_animation()) {
1448  anim->my_unit->anim_comp().get_animation()->restart_animation();
1449  }
1450  }
1451 }
1452 
1454 {
1455  for(std::vector<anim_elem>::iterator anim = animated_units_.begin(); anim != animated_units_.end();++anim) {
1456  anim->my_unit->anim_comp().set_standing();
1457  }
1458 }
play_controller * controller
Definition: resources.cpp:21
boost::intrusive_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:30
child_itors child_range(const std::string &key)
Definition: config.cpp:613
Describe a unit's animation sequence.
Definition: frame.hpp:204
static DIRECTION parse_direction(const std::string &str)
Definition: location.cpp:69
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
animation_cursor * parent
Definition: animation.cpp:95
void start_animations()
Definition: animation.cpp:1346
particule(int start_time=0, const frame_builder &builder=frame_builder())
Definition: animation.hpp:89
void wait_until(int animation_time) const
Definition: animation.cpp:1380
bool matches_filter(const config &filter) const
Returns whether or not *this matches the given filter.
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3536
std::vector< hit_type > hits_
Definition: animation.hpp:138
Definition: unit.hpp:95
void set_end_time(int ending_time)
t_list read_list(const std::string &str, const t_layer filler)
Reads a list of terrains from a string, when reading the.
keep most parameters in a separate class to simplify handling of large number of parameters handling ...
Definition: frame.hpp:159
bool need_update() const
Definition: animation.cpp:907
GLenum GLint * range
Definition: glew.h:3025
bool need_update() const
Definition: animation.cpp:860
int get_animation_time_potential() const
Definition: animation.cpp:1420
const GLfloat * c
Definition: glew.h:12741
int pos
Definition: formula.cpp:800
void override(int start_time, int duration, const cycle_state cycles, const std::string &highlight="", const std::string &blend_ratio="", Uint32 blend_color=0, const std::string &offset="", const std::string &layer="", const std::string &modifiers="")
Definition: animation.cpp:830
std::string debug() const
Definition: animation.cpp:1091
std::vector< map_location::DIRECTION > directions_
Definition: animation.hpp:131
animation_cursor(const config &cfg)
Definition: animation.cpp:96
config::all_children_itors itors
Definition: animation.cpp:93
static void add_anims(std::vector< unit_animation > &animations, const config &cfg)
Definition: animation.cpp:618
int get_end_time() const
Definition: animation.cpp:960
std::vector< config > secondary_attack_filter_
Definition: animation.hpp:137
static void prepare_single_animation(const config &anim_cfg, animation_branches &expanded_anims)
Definition: animation.cpp:200
void start_animation(int start_time)
Definition: animation.cpp:1256
int get_begin_time() const
Definition: animation.cpp:970
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glew.h:3783
void add_frame(int duration, const unit_frame &value, bool force_change=false)
Definition: animation.hpp:43
void clear_haloes()
Definition: animation.cpp:1040
const unit_animation * animation
Definition: animation.hpp:219
int get_animation_time() const
Definition: animation.hpp:53
std::vector< int > value_
Definition: animation.hpp:135
void add_frame(int duration, const unit_frame &value, bool force_change=false)
Adds a frame to an animation.
std::vector< std::string > debug_strings() const
Definition: frame.hpp:217
bool tile_nearly_on_screen(const map_location &loc) const
Checks if location loc or one of the adjacent tiles is visible on screen.
Definition: display.cpp:2345
void play_slice(bool is_delay_enabled=true)
bool animation_finished_potential() const
Definition: animation.cpp:940
Audio output for sound and music.
Definition: sound.cpp:43
GLenum src
Definition: glew.h:2392
#define d
std::string debug() const
Definition: config.cpp:1438
All parameters from a frame at a given instant.
Definition: frame.hpp:71
size_t get_frames_count() const
bool empty() const
Tests for an attribute that either was never set or was set to "".
Definition: config.cpp:375
std::pair< const_child_iterator, const_child_iterator > const_child_itors
Definition: config.hpp:214
Variant for storing WML attributes.
Definition: config.hpp:223
map_location dst_
Definition: animation.hpp:144
int get_begin_time() const
void restart_animation()
Definition: animated.hpp:63
void pause_animation()
Definition: animation.cpp:1009
bool would_end() const
Definition: animation.cpp:1371
GLintptr offset
Definition: glew.h:1650
tdrawing_layer
The layers to render something on.
Definition: display.hpp:864
bool does_not_change() const
Definition: frame.hpp:214
std::set< map_location > get_overlaped_hex(const int frame_time, const map_location &src, const map_location &dst, const frame_parameters &animation_val, const frame_parameters &engine_val) const
Definition: frame.cpp:751
const unit_frame & get_last_frame() const
static void add_simple_anim(std::vector< unit_animation > &animations, const config &cfg, char const *tag_name, char const *apply_to, display::tdrawing_layer layer=display::LAYER_UNIT_DEFAULT, bool offscreen=true)
Definition: animation.cpp:599
void update_last_draw_time(double acceleration=0)
GLuint64EXT * result
Definition: glew.h:10727
unit_animation * get_animation() const
Get a pointer to the current animation.
void restart_animation()
Definition: animation.cpp:1444
unit_animation()
Shouldn't be used so only declared.
int get_end_time() const
Definition: animation.cpp:1424
GLenum GLenum GLuint GLint GLint layer
Definition: glew.h:3455
static const std::vector< std::string > & all_tag_names()
Definition: animation.cpp:65
void replace_anim_if_invalid(const unit *animated_unit, const std::string &event, const map_location &src=map_location::null_location(), const map_location &dst=map_location::null_location(), const int value=0, bool with_bars=false, const std::string &text="", const Uint32 text_color=0, const unit_animation::hit_type hit_type=unit_animation::INVALID, const attack_type *attack=nullptr, const attack_type *second_attack=nullptr, int value2=0)
Definition: animation.cpp:1315
const GLdouble * v
Definition: glew.h:1359
GLsizei const GLfloat * value
Definition: glew.h:1817
all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:1127
GLenum GLenum dst
Definition: glew.h:2392
std::set< map_location > overlaped_hex_
Definition: animation.hpp:148
int get_current_frame_begin_time() const
Definition: animation.hpp:64
std::pair< all_children_iterator, all_children_iterator > all_children_itors
Definition: config.hpp:665
config & add_child(const std::string &key)
Definition: config.cpp:743
std::vector< config::all_children_iterator > children
Definition: animation.cpp:78
default layer for missile frames
Definition: display.hpp:889
unit_const_ptr my_unit
Definition: animation.hpp:218
default layer for drawing moving units
Definition: display.hpp:884
int get_animation_duration() const
std::vector< config > secondary_unit_filter_
Definition: animation.hpp:130
std::vector< std::string > event_
Definition: animation.hpp:134
const T & get_frame(size_t n) const
unit_animation_component & anim_comp() const
Definition: unit.hpp:276
GLfloat GLfloat p
Definition: glew.h:12766
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:135
GLuint const GLuint * names
Definition: glew.h:2552
GLuint GLuint GLsizei count
Definition: glew.h:1221
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:47
const unit_map & get_units() const
Definition: display.hpp:121
void restart_animation()
Definition: animation.cpp:1018
void pause_animation()
Definition: animated.hpp:62
int matches(const display &disp, const map_location &loc, const map_location &second_loc, const unit *my_unit, const std::string &event="", const int value=0, hit_type hit=INVALID, const attack_type *attack=nullptr, const attack_type *second_attack=nullptr, int value2=0) const
Definition: animation.cpp:377
Encapsulates the map of the game.
Definition: location.hpp:38
const std::string & get_filename() const
Definition: image.hpp:86
int get_end_time() const
double turbo_speed() const
Definition: display.cpp:2631
Reserve layers to be selected for WML.
Definition: display.hpp:873
const std::string & get_modifications() const
Definition: image.hpp:90
default layer for drawing units
Definition: display.hpp:875
void new_animation_frame()
animation_branches branches
Definition: animation.cpp:94
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
map_location::DIRECTION facing() const
Definition: unit.hpp:278
static Uint32 rgb(Uint8 red, Uint8 green, Uint8 blue)
Definition: display.hpp:176
friend std::ostream & operator<<(std::ostream &outstream, const unit_animation &u_animation)
Definition: animation.cpp:1098
std::list< animation_branch > animation_branches
Definition: animation.cpp:89
std::vector< std::string > names
Definition: animation.cpp:59
void pause_animation()
Definition: animation.cpp:1435
particule unit_anim_
Definition: animation.hpp:141
map_location src_
Definition: animation.hpp:143
std::set< map_location > get_overlaped_hex(const frame_parameters &value, const map_location &src, const map_location &dst)
Definition: animation.cpp:1243
size_t i
Definition: function.cpp:1057
bool terrain_matches(const t_terrain &src, const t_terrain &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
int duration() const
Definition: frame.hpp:213
std::vector< int > value2_
Definition: animation.hpp:139
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
bool does_not_change() const
Definition: frame.cpp:478
static void fill_initial_animations(std::vector< unit_animation > &animations, const config &cfg)
Definition: animation.cpp:469
bool animation_finished() const
Returns true if the current animation was finished.
void add_animation(const unit *animated_unit, const unit_animation *animation, const map_location &src=map_location::null_location(), bool with_bars=false, const std::string &text="", const Uint32 text_color=0)
Definition: animation.cpp:1294
std::vector< config > unit_filter_
Definition: animation.hpp:129
t_translation::t_terrain get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:341
std::vector< config > primary_attack_filter_
Definition: animation.hpp:136
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:3448
std::map< std::string, particule > sub_anims_
Definition: animation.hpp:140
void set_begin_time(int new_begin_time)
void update_parameters(const map_location &src, const map_location &dst)
Definition: animation.cpp:1004
void override(int duration, const std::string &highlight="", const std::string &blend_ratio="", Uint32 blend_color=0, const std::string &offset="", const std::string &layer="", const std::string &modifiers="")
allow easy chained modifications will raised assert if used after initialization
Definition: frame.cpp:546
const gamemap & get_map() const
Definition: display.hpp:92
tristate primary_frame
Definition: frame.hpp:97
const unit_animation * choose_animation(const display &disp, const map_location &loc, const std::string &event, const map_location &second_loc=map_location::null_location(), const int damage=0, const unit_animation::hit_type hit_type=unit_animation::INVALID, const attack_type *attack=nullptr, const attack_type *second_attack=nullptr, int swing_num=0)
Chooses an appropriate animation from the list of known animations.
bool find(E event, F functor)
Tests whether an event handler is available.
cl_event event
Definition: glew.h:3070
void set_all_standing()
Definition: animation.cpp:1453
config merge() const
Definition: animation.cpp:79
A variable-expanding proxy for the config class.
Definition: variable.hpp:36
static animation_branches prepare_animation(const config &cfg, const std::string &animation_tag)
Definition: animation.cpp:259
frame_parsed_parameters parameters_
Definition: animation.hpp:122
static void delay(unsigned int milliseconds)
Definition: video.cpp:490
Definition: frame.hpp:68
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
void redraw(frame_parameters &value, halo::manager &halo_man)
Definition: animation.cpp:1027
void update_last_draw_time()
Definition: animation.cpp:950
unit_iterator find(size_t id)
Definition: map.cpp:285
bool valid() const
Definition: map.hpp:229
void redraw(const frame_parameters &value, const map_location &src, const map_location &dst, halo::manager &halo_man)
Definition: animation.cpp:1216
int get_animation_time() const
Definition: animation.cpp:1416
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
t_translation::t_list terrain_types_
Definition: animation.hpp:128
bool play_offscreen_
Definition: animation.hpp:147
bool animation_finished_potential() const
bool animation_finished() const
Definition: animation.cpp:930
animation_cursor(const config &cfg, animation_cursor *p)
Definition: animation.cpp:101
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool need_minimal_update() const
Definition: animation.cpp:917
void redraw(const int frame_time, bool on_start_time, bool in_scope_of_frame, const map_location &src, const map_location &dst, halo::handle &halo_id, halo::manager &halo_man, const frame_parameters &animation_val, const frame_parameters &engine_val) const
Definition: frame.cpp:630
config & add_child_at(const std::string &key, const config &val, unsigned index)
Definition: config.cpp:773
void wait_for_end() const
Definition: animation.cpp:1399
void start_animation(int start_time, const map_location &src=map_location::null_location(), const map_location &dst=map_location::null_location(), const std::string &text="", const Uint32 text_color=0, const bool accelerate=true)
Definition: animation.cpp:980
bool need_minimal_update() const
Definition: animation.cpp:868
bool propagate_invalidation(const std::set< map_location > &locs)
If this set is partially invalidated, invalidate all its hexes.
Definition: display.cpp:3563
bool invalidate(frame_parameters &value)
Definition: animation.cpp:1049
static game_display * get_singleton()
boost::shared_ptr< halo_record > handle
Definition: halo.hpp:34
GLclampf f
Definition: glew.h:3024
void start_animation(int start_time, bool cycles=false)
Starts an animation cycle.