wesnoth/src/unit_animation.cpp

224 lines
6.6 KiB
C++

/* $Id: unit_animation.cpp 9735 2006-01-18 18:31:24Z boucman $ */
/*
Copyright (C) 2006 by Jeremy Rosen <jeremy.rosen@enst-bretagne.fr>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "global.hpp"
#include "game_config.hpp"
#include "gettext.hpp"
#include "log.hpp"
#include "unit_animation.hpp"
#include "unit_types.hpp"
#include "util.hpp"
#include "wassert.hpp"
#include "serialization/string_utils.hpp"
#include "color_range.hpp"
#include <algorithm>
#include <cstdlib>
#include <iostream>
config unit_animation::prepare_animation(const config &cfg,const std::string animation_tag)
{
config expanded_animations;
config::const_child_itors all_anims = cfg.child_range(animation_tag);
config::const_child_iterator current_anim;
std::vector<config> unexpanded_anims;
// store all the anims we have to analyze
for(current_anim = all_anims.first; current_anim != all_anims.second ; current_anim++) {
unexpanded_anims.push_back(**current_anim);
}
while(!unexpanded_anims.empty()) {
// take one anim out of the unexpanded list
const config analyzed_anim = unexpanded_anims.back();
unexpanded_anims.pop_back();
config::all_children_iterator child = analyzed_anim.ordered_begin();
config expanded_anim;
expanded_anim.values = analyzed_anim.values;
while(child != analyzed_anim.ordered_end()) {
if(*(*child).first == "if") {
std::vector<config> to_add;
config expanded_chunk = expanded_anim;
// add the content of if
expanded_chunk.append(*(*child).second);
to_add.push_back(expanded_chunk);
child++;
if(*(*child).first == "else") {
while(*(*child).first == "else") {
expanded_chunk = expanded_anim;
// add the content of else to the stored one
expanded_chunk.append(*(*child).second);
to_add.push_back(expanded_chunk);
// store the partially expanded string for later analyzis
child++;
}
} else {
// add an animw with the if part removed
to_add.push_back(expanded_anim);
}
// copy the end of the anim "as is" other if will be treated later
while(child != analyzed_anim.ordered_end()) {
for(std::vector<config>::iterator itor= to_add.begin(); itor != to_add.end();itor++) {
itor->add_child(*(*child).first,*(*child).second);
}
child++;
}
unexpanded_anims.insert(unexpanded_anims.end(),to_add.begin(),to_add.end());
// stop this one which had an if we have resolved, parse the next one
continue;
} else {
// add the current node
expanded_anim.add_child(*(*child).first,*(*child).second);
child++;
}
}
expanded_animations.add_child(animation_tag,expanded_anim);
}
return expanded_animations;
}
unit_animation::unit_animation(const std::string image )
{
add_frame(0,unit_frame(image));
}
unit_animation::unit_animation(const config& cfg,const std::string frame_string ):terrain_types(utils::split(cfg["terrain"])){
config::const_child_itors range = cfg.child_range(frame_string);
int last_end = INT_MIN;
for(; range.first != range.second; ++range.first) {
add_frame(atoi((**range.first)["begin"].c_str()), unit_frame(**range.first));
last_end = maximum<int>(atoi((**range.first)["end"].c_str()), last_end);
}
add_frame(last_end);
const std::vector<std::string>& my_directions = utils::split(cfg["direction"]);
for(std::vector<std::string>::const_iterator i = my_directions.begin(); i != my_directions.end(); ++i) {
const gamemap::location::DIRECTION d = gamemap::location::parse_direction(*i);
directions.push_back(d);
}
/* warn on deprecated WML */
if(cfg.child("sound")) {
LOG_STREAM(err, config) << "an animation uses the deprecated [sound] tag, please include sound in the [frame] tag\n";
}
}
unit_animation::unit_animation(const std::string image, int begin_at, int end_at, const std::string image_diagonal,const std::string halo,int halo_x,int halo_y)
{
add_frame(begin_at, unit_frame(image,image_diagonal,begin_at,end_at,0,"0.0","1.0",halo,halo_x,halo_y));
if (end_at != begin_at) {
add_frame(end_at);
}
}
unit_animation::unit_animation(const std::string image, const std::string halo,int halo_x,int halo_y)
{
add_frame(0, unit_frame(image,"",0,0,0,"0.0","1.0",halo,halo_x,halo_y));
if (!halo.empty()) {
add_frame();
}
}
int unit_animation::matches(const std::string &terrain,const gamemap::location::DIRECTION dir) const
{
int result = 0;
if(terrain_types.empty()== false) {
if (std::find(terrain_types.begin(),terrain_types.end(),terrain)== terrain_types.end()) {
return -1;
} else {
result ++;
}
}
if(directions.empty()== false) {
if (std::find(directions.begin(),directions.end(),dir)== directions.end()) {
return -1;
} else {
result ++;
}
}
return result;
}
fighting_animation::fighting_animation(const config& cfg) :unit_animation(cfg), range(utils::split(cfg["range"])),
damage_type(utils::split(cfg["damage_type"])), special(utils::split(cfg["attack_special"]))
{
std::vector<std::string> hits_str = utils::split(cfg["hits"]);
std::vector<std::string>::iterator hit;
for(hit=hits_str.begin() ; hit != hits_str.end() ; hit++) {
if(*hit == "yes" || *hit == "hit") {
hits.push_back(HIT);
}
if(*hit == "no" || *hit == "miss") {
hits.push_back(MISS);
}
if(*hit == "kill" ) {
hits.push_back(KILL);
}
}
}
int fighting_animation::matches(const std::string &terrain,gamemap::location::DIRECTION dir,hit_type hit,const attack_type* attack) const
{
int result = unit_animation::matches(terrain,dir);
if(!attack) {
if(damage_type.empty() && special.empty())
return result;
else
return -1;
}
if(hits.empty() == false ) {
if (std::find(hits.begin(),hits.end(),hit)== hits.end()) {
return -1;
} else {
result ++;
}
}
if(range.empty()== false) {
if (std::find(range.begin(),range.end(),attack->range())== range.end()) {
return -1;
} else {
result ++;
}
}
if(damage_type.empty()== false) {
if (std::find(damage_type.begin(),damage_type.end(),attack->type())== damage_type.end()) {
return -1;
} else {
result ++;
}
}
if(special.empty()== false) {
bool found = false;
std::vector<std::string> at_specials = utils::split(attack->weapon_specials(true));
for(std::vector<std::string>::const_iterator sp_it = special.begin(); sp_it != special.end(); ++sp_it) {
if (std::find(at_specials.begin(),at_specials.end(),*sp_it) != at_specials.end()) {
result ++;
found = true;
}
}
if(!found) {
return -1;
}
}
return result;
}