make offset a progressive param.

I have changed the Elvish Shaman line as an example, but it needs a
better missile
This commit is contained in:
Jérémy Rosen 2006-09-10 08:51:55 +00:00
parent 904ae6dbfa
commit e77114fe79
11 changed files with 179 additions and 128 deletions

View file

@ -43,6 +43,8 @@ Version 1.3-svn:
* add progressive paramteters, allow to specify a value that will move
continuously in an animation
* alpha blending is our first progressive parameter
* new parameter in frames, offset. It allows to specify the position
relative to the faced hex
* units can now have a recruit animation that will be played on unit
recruit.
* units now have idle animations when they arn't used for some time

View file

@ -60,6 +60,7 @@ Special Notes:"+{SPECIAL_NOTES_SLOW}+{SPECIAL_NOTES_CURES}
icon=attacks/entangle.png
[animation]
[missile_frame]
offset=1.0
begin=-200
end=0
image="projectiles/entangle.png"

View file

@ -98,6 +98,7 @@ Special Notes:"+{SPECIAL_NOTES_MAGICAL}+{SPECIAL_NOTES_SLOW}
range=ranged
[animation]
[missile_frame]
offset=1.0
begin=-200
end=50
image="projectiles/entangle.png"

View file

@ -62,6 +62,7 @@ Special Notes:"+{SPECIAL_NOTES_SLOW}+{SPECIAL_NOTES_HEALS}
range=ranged
[animation]
[missile_frame]
offset=1.0
begin=-250
end=0
image="projectiles/entangle.png"

View file

@ -63,6 +63,7 @@ Special Notes:"+{SPECIAL_NOTES_SLOW}+{SPECIAL_NOTES_CURES}
icon=attacks/entangle.png
[animation]
[missile_frame]
offset=1.0
begin=-150
end=0
image="projectiles/entangle.png"

View file

@ -98,6 +98,7 @@ Special Notes:"+{SPECIAL_NOTES_MAGICAL}+{SPECIAL_NOTES_SLOW}
range=ranged
[animation]
[missile_frame]
offset=1.0
begin=-200
end=50
image="projectiles/entangle.png"

View file

@ -1354,7 +1354,7 @@ void unit::read(const config& cfg)
}
if(healing_animations_.empty()) {
healing_animations_.push_back(healing_animation(unit_frame(image_healing(),0,150,
"1.0",0,"",image_halo_healing(),0,0)));
"1.0","",0,"",image_halo_healing(),0,0)));
// always have a healing animation
}
@ -1378,7 +1378,7 @@ void unit::read(const config& cfg)
levelin_animations_.push_back(levelin_animation(**levelin_anim));
}
if(levelin_animations_.empty()) {
levelout_animations_.push_back(levelout_animation(unit_frame(absolute_image(),0,600,"1.0",display::rgb(255,255,255),"1~0:600")));
levelout_animations_.push_back(levelout_animation(unit_frame(absolute_image(),0,600,"1.0","",display::rgb(255,255,255),"1~0:600")));
// always have a levelin animation
}
@ -1386,7 +1386,7 @@ void unit::read(const config& cfg)
levelout_animations_.push_back(levelout_animation(**levelout_anim));
}
if(levelout_animations_.empty()) {
levelout_animations_.push_back(levelout_animation(unit_frame(absolute_image(),0,600,"1.0",display::rgb(255,255,255),"0~1:600")));
levelout_animations_.push_back(levelout_animation(unit_frame(absolute_image(),0,600,"1.0","",display::rgb(255,255,255),"0~1:600")));
// always have a levelout animation
}
@ -1609,7 +1609,7 @@ void unit::set_defending(const display &disp,const gamemap::location& loc, int d
int anim_time = anim_->get_last_frame_time();
const std::string my_image = anim_->get_last_frame().image();
if(damage) {
anim_->add_frame(anim_time,unit_frame(my_image,anim_time,anim_time+100,"1.0",display::rgb(255,0,0),"0.5:50,0.0:50"));
anim_->add_frame(anim_time,unit_frame(my_image,anim_time,anim_time+100,"1.0","",display::rgb(255,0,0),"0.5:50,0.0:50"));
anim_time+=100;
}
anim_->add_frame(anim_time);
@ -1719,7 +1719,7 @@ void unit::set_healed(const display &disp,const gamemap::location& /*loc*/, int
delete anim_;
anim_ = NULL;
}
anim_ = new unit_animation(unit_frame(absolute_image(),0,240,"1.0",display::rgb(255,255,255),"0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30"));
anim_ = new unit_animation(unit_frame(absolute_image(),0,240,"1.0","",display::rgb(255,255,255),"0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30"));
anim_->start_animation(anim_->get_first_frame_time(), 1, disp.turbo_speed());
frame_begin_time = anim_->get_first_frame_time() -1;
anim_->update_current_frame();
@ -1732,7 +1732,7 @@ void unit::set_poisoned(const display &disp,const gamemap::location& /*loc*/, in
delete anim_;
anim_ = NULL;
}
anim_ = new unit_animation(unit_frame(absolute_image(),0,240,"1.0",display::rgb(0,255,0),"0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30"));
anim_ = new unit_animation(unit_frame(absolute_image(),0,240,"1.0","",display::rgb(0,255,0),"0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30"));
anim_->start_animation(anim_->get_first_frame_time(), 1, disp.turbo_speed());
frame_begin_time = anim_->get_first_frame_time() -1;
anim_->update_current_frame();
@ -1845,8 +1845,6 @@ void unit::redraw_unit(display& disp,gamemap::location hex)
const double xdst = disp.get_location_x(dst);
const double ydst = disp.get_location_y(dst);
const int x = int(offset_*xdst + (1.0-offset_)*xsrc);
const int y = int(offset_*ydst + (1.0-offset_)*ysrc);
if(!anim_) set_standing(disp,hex);
const gamemap::TERRAIN terrain = map.get_terrain(hex);
@ -1861,6 +1859,10 @@ void unit::redraw_unit(display& disp,gamemap::location hex)
else current_frame = anim_->get_current_frame();
image_name = current_frame.image();
double tmp_offset = current_frame.offset(anim_->get_animation_time());
if(tmp_offset == -20.0) tmp_offset = offset_;
const int x = int(tmp_offset*xdst + (1.0-tmp_offset)*xsrc);
const int y = int(tmp_offset*ydst + (1.0-tmp_offset)*ysrc);
if(frame_begin_time != current_frame.begin_time()) {
frame_begin_time = current_frame.begin_time();
if(!current_frame.sound().empty()) {

View file

@ -269,12 +269,10 @@ bool unit_attack_ranged(display& disp, unit_map& units,
defender.set_defending(disp,b,damage,&attack,swing);
// min of attacker, defender, missile and -200
const int start_time = minimum<int>(
minimum<int>(
minimum<int>(defender.get_animation()->get_first_frame_time(),
missile_animation.get_first_frame_time()),
attacker.get_animation()->get_first_frame_time()),
-200);
int start_time = -200;
start_time = minimum<int>(start_time,defender.get_animation()->get_first_frame_time());
start_time = minimum<int>(start_time,missile_animation.get_first_frame_time());
start_time = minimum<int>(start_time,attacker.get_animation()->get_first_frame_time());
missile_animation.start_animation(start_time,1,acceleration);
defender.restart_animation(disp,start_time);
attacker.restart_animation(disp,start_time);
@ -287,11 +285,17 @@ bool unit_attack_ranged(display& disp, unit_map& units,
defender.state() != unit::STATE_STANDING ||
!missile_animation.animation_finished() ||
(leader_loc.valid() && leader->second.state() != unit::STATE_STANDING))
){
const double pos = animation_time < missile_animation.get_first_frame_time()?1.0:
){
const unit_frame& missile_frame = missile_animation.get_current_frame();
/* double pos = missile_frame.offset(missile_animation.get_animation_time());
if(pos!=-20.0) pos = animation_time < missile_animation.get_first_frame_time()?1.0:
double(animation_time)/double(missile_animation.get_first_frame_time());
const int posx = int(pos*xsrc + (1.0-pos)*xdst);
const int posy = int(pos*ysrc + (1.0-pos)*ydst);
else pos= 1.0-pos;*/
double pos = missile_frame.offset(animation_time);
if(pos == -20.0) {
pos = double(animation_time -missile_animation.get_first_frame_time())/
double(missile_animation.get_last_frame_time()-missile_animation.get_first_frame_time());
}
disp.invalidate(b);
disp.invalidate(a);
if(leader_loc.valid()) disp.invalidate(leader_loc);
@ -299,10 +303,12 @@ bool unit_attack_ranged(display& disp, unit_map& units,
halo::remove(missile_frame_halo);
missile_halo = 0;
missile_frame_halo = 0;
if(animation_time < missile_animation.get_last_frame_time() && pos < 1.0 && (!disp.fogged(b.x,b.y) || !disp.fogged(a.x,a.y))) {
if(animation_time > missile_animation.get_first_frame_time() &&
animation_time < missile_animation.get_last_frame_time() &&
(!disp.fogged(b.x,b.y) || !disp.fogged(a.x,a.y))) {
const int posx = int(pos*xdst + (1.0-pos)*xsrc);
const int posy = int(pos*ydst + (1.0-pos)*ysrc);
missile_animation.update_current_frame();
const unit_frame& missile_frame = missile_animation.get_current_frame();
std::string missile_image= missile_frame.image();
const int d = disp.hex_size() / 2;
if(dir == unit_animation::VERTICAL) {
@ -338,13 +344,13 @@ bool unit_attack_ranged(display& disp, unit_map& units,
disp.draw();
events::pump();
if(attacker.get_animation()->animation_finished()) {
attacker.set_standing(disp,a,false);
attacker.set_standing(disp,a,false);
}
if(defender.get_animation()->animation_finished()) {
defender.set_standing(disp,b,false);
defender.set_standing(disp,b,false);
}
if(leader_loc.valid() && leader->second.get_animation()->animation_finished() ) {
leader->second.set_standing(disp,leader_loc,true);
leader->second.set_standing(disp,leader_loc,true);
}
disp.non_turbo_delay();
// we use missile animation because it's the only one not reseted in the middle to go to standing

View file

@ -13,140 +13,148 @@
#include <global.hpp>
#include <unit_frame.hpp>
// a list of element to return at different time during an anim
std::vector<std::pair<std::string,int> > prepare_timed_list(const std::string & data,int duration)
progressive_string::progressive_string(const std::string & data,int duration)
{
const std::vector<std::string> first_pass = utils::split(data);
const int time_chunk = maximum<int>(duration / (first_pass.size()?first_pass.size():1),1);
std::vector<std::string>::const_iterator tmp;
std::vector<std::pair<std::string,int> > result;
for(tmp=first_pass.begin();tmp != first_pass.end() ; tmp++) {
std::vector<std::string> second_pass = utils::split(*tmp,':');
if(second_pass.size() > 1) {
result.push_back(std::pair<std::string,int>(second_pass[0],atoi(second_pass[1].c_str())));
data_.push_back(std::pair<std::string,int>(second_pass[0],atoi(second_pass[1].c_str())));
} else {
result.push_back(std::pair<std::string,int>(second_pass[0],time_chunk));
data_.push_back(std::pair<std::string,int>(second_pass[0],time_chunk));
}
}
return result;
}
const std::string get_current_element_string(const std::vector<std::pair<std::string,int> > &data, int current_time)
{
int time = 0;
unsigned int sub_halo = 0;
if(data.empty()) return std::string();
while(time < current_time&& sub_halo < data.size()) {
time += data[sub_halo].second;
sub_halo++;
}
if(sub_halo > 0) sub_halo --;
if(sub_halo >= data.size()) sub_halo = data.size();
return data[sub_halo].first;
}
std::vector<std::pair<std::pair<double,double>,int> > prepare_progressive_double(const std::string &data, int duration)
{
std::vector<std::pair<std::string,int> > first_pass = prepare_timed_list(data,duration);
std::vector<std::pair<std::string,int> >::const_iterator tmp;
std::vector<std::pair<std::pair<double,double>,int> > result;
for(tmp=first_pass.begin();tmp != first_pass.end() ; tmp++) {
std::vector<std::string> range = utils::split(tmp->first,'~');
result.push_back(std::pair<std::pair<double,double>,int> (
std::pair<double,double>(
atof(range[0].c_str()),
atof(range.size()>1?range[1].c_str():range[0].c_str())),
tmp->second));
}
return result;
}
const double get_current_element_double(const std::vector<std::pair<std::pair<double,double>,int> > &data, int current_time)
{
int time = 0;
unsigned int sub_halo = 0;
if(data.empty()) return 0;
while(time < current_time&& sub_halo < data.size()) {
time += data[sub_halo].second;
sub_halo++;
}
if(sub_halo > 0) {
sub_halo--;
time -= data[sub_halo].second;
}
if(sub_halo >= data.size()) {
sub_halo = data.size();
time = current_time; // never more than max allowed
}
const double first = data[sub_halo].first.first;
const double second = data[sub_halo].first.second;
return ( double(current_time - time)/(double)(data[sub_halo].second))*(second - first)+ first;
}
int duration_string(const std::vector<std::pair<std::string,int> > &data)
int progressive_string::duration() const
{
int total =0;
std::vector<std::pair<std::string,int> >::const_iterator cur_halo;
for(cur_halo = data.begin() ; cur_halo != data.end() ; cur_halo++) {
for(cur_halo = data_.begin() ; cur_halo != data_.end() ; cur_halo++) {
total += cur_halo->second;
}
return total;
}
int duration_double(const std::vector<std::pair<std::pair<double,double>,int> > &data)
const std::string grr;
const std::string& progressive_string::get_current_element( int current_time)const
{
int time = 0;
unsigned int sub_halo = 0;
if(data_.empty()) return grr;
while(time < current_time&& sub_halo < data_.size()) {
time += data_[sub_halo].second;
sub_halo++;
}
if(sub_halo > 0) sub_halo --;
if(sub_halo >= data_.size()) sub_halo = data_.size();
return data_[sub_halo].first;
}
progressive_double::progressive_double(const std::string &data, int duration)
{
const std::vector<std::string> first_split = utils::split(data);
const int time_chunk = maximum<int>(duration / (first_split.size()?first_split.size():1),1);
std::vector<std::string>::const_iterator tmp;
std::vector<std::pair<std::string,int> > first_pass;
for(tmp=first_split.begin();tmp != first_split.end() ; tmp++) {
std::vector<std::string> second_pass = utils::split(*tmp,':');
if(second_pass.size() > 1) {
first_pass.push_back(std::pair<std::string,int>(second_pass[0],atoi(second_pass[1].c_str())));
} else {
first_pass.push_back(std::pair<std::string,int>(second_pass[0],time_chunk));
}
}
std::vector<std::pair<std::string,int> >::const_iterator tmp2;
for(tmp2=first_pass.begin();tmp2 != first_pass.end() ; tmp2++) {
std::vector<std::string> range = utils::split(tmp2->first,'~');
data_.push_back(std::pair<std::pair<double,double>,int> (
std::pair<double,double>(
atof(range[0].c_str()),
atof(range.size()>1?range[1].c_str():range[0].c_str())),
tmp2->second));
}
}
const double progressive_double::get_current_element(int current_time)const
{
int time = 0;
unsigned int sub_halo = 0;
if(data_.empty()) return 0;
while(time < current_time&& sub_halo < data_.size()) {
time += data_[sub_halo].second;
sub_halo++;
}
if(sub_halo > 0) {
sub_halo--;
time -= data_[sub_halo].second;
}
if(sub_halo >= data_.size()) {
sub_halo = data_.size();
time = current_time; // never more than max allowed
}
const double first = data_[sub_halo].first.first;
const double second = data_[sub_halo].first.second;
return ( double(current_time - time)/(double)(data_[sub_halo].second))*(second - first)+ first;
}
int progressive_double::duration() const
{
int total =0;
std::vector<std::pair<std::pair<double,double>,int> >::const_iterator cur_halo;
for(cur_halo = data.begin() ; cur_halo != data.end() ; cur_halo++) {
for(cur_halo = data_.begin() ; cur_halo != data_.end() ; cur_halo++) {
total += cur_halo->second;
}
return total;
}
unit_frame::unit_frame() :
xoffset_(0), image_(), image_diagonal_(),halo_(), sound_(),
image_(), image_diagonal_(),halo_(), sound_(),
halo_x_(0), halo_y_(0), begin_time_(0), end_time_(0),
blend_with_(0),blend_ratio_(),
highlight_ratio_()
highlight_ratio_("1.0"),offset_("-20")
{
highlight_ratio_ = prepare_progressive_double("1.0",0);
}
unit_frame::unit_frame(const std::string& str, int begin,int end,
const std::string& highlight,
const std::string& highlight, const std::string& offset,
Uint32 blend_color, const std::string& blend_rate,
std::string in_halo, int halox, int haloy,
const std::string & diag) :
xoffset_(0), image_(str),image_diagonal_(diag),
halo_(),halo_x_(halox), halo_y_(haloy),
image_(str),image_diagonal_(diag),
halo_(in_halo,end_time_ - begin_time_),halo_x_(halox), halo_y_(haloy),
begin_time_(begin), end_time_(end),
blend_with_(blend_color)
blend_with_(blend_color), blend_ratio_(blend_rate,end_time_ - begin_time_),
highlight_ratio_(highlight,end_time_ - begin_time_)
{
halo_ = prepare_timed_list(in_halo,end_time_ - begin_time_);
blend_ratio_ = prepare_progressive_double(blend_rate,end_time_ - begin_time_);
highlight_ratio_ = prepare_progressive_double(highlight,end_time_ - begin_time_);
// let's decide of duration ourselves
if(offset.empty()) offset_=progressive_double("-20",end_time_-begin_time_);
else offset_=progressive_double(offset,end_time_-begin_time_);
end_time_ = end;
end_time_ = maximum<int>(end_time_,begin + duration_double(highlight_ratio_));
end_time_ = maximum<int>(end_time_,begin + duration_double(blend_ratio_));
end_time_ = maximum<int>(end_time_,begin + duration_string(halo_));
end_time_ = maximum<int>(end_time_,begin + highlight_ratio_.duration());
end_time_ = maximum<int>(end_time_,begin + blend_ratio_.duration());
end_time_ = maximum<int>(end_time_,begin + halo_.duration());
end_time_ = maximum<int>(end_time_,begin + offset_.duration());
}
unit_frame::unit_frame(const config& cfg)
{
xoffset_ = atoi(cfg["xoffset"].c_str());
image_ = cfg["image"];
image_diagonal_ = cfg["image_diagonal"];
halo_x_ = atoi(cfg["halo_x"].c_str());
@ -154,26 +162,32 @@ unit_frame::unit_frame(const config& cfg)
sound_ = cfg["sound"];
begin_time_ = atoi(cfg["begin"].c_str());
end_time_ = atoi(cfg["end"].c_str());
halo_ = prepare_timed_list(cfg["halo"],end_time_-begin_time_);
halo_ = progressive_string(cfg["halo"],end_time_-begin_time_);
blend_with_= 0;
blend_ratio_ = prepare_progressive_double(cfg["blend_ratio"],end_time_-begin_time_);
highlight_ratio_ = prepare_progressive_double(cfg["alpha"].empty()?"1.0":cfg["alpha"],end_time_-begin_time_);
blend_ratio_ = progressive_double(cfg["blend_ratio"],end_time_-begin_time_);
highlight_ratio_ = progressive_double(cfg["alpha"].empty()?"1.0":cfg["alpha"],end_time_-begin_time_);
offset_ = progressive_double(cfg["offset"].empty()?"-20":cfg["offset"],end_time_-begin_time_);
}
const std::string unit_frame::halo(int current_time) const
const std::string &unit_frame::halo(int current_time) const
{
return get_current_element_string(halo_,current_time - begin_time_);
return halo_.get_current_element(current_time - begin_time_);
}
double unit_frame::blend_ratio(int current_time) const
{
return get_current_element_double(blend_ratio_,current_time - begin_time_);
return blend_ratio_.get_current_element(current_time - begin_time_);
}
fixed_t unit_frame::highlight_ratio(int current_time) const
{
return ftofxp(get_current_element_double(highlight_ratio_,current_time - begin_time_));
return ftofxp(highlight_ratio_.get_current_element(current_time - begin_time_));
}
double unit_frame::offset(int current_time) const
{
return offset_.get_current_element(current_time - begin_time_);
}

View file

@ -22,23 +22,43 @@
#include <string>
#include <vector>
//
class progressive_string {
public:
progressive_string(const std::string& data = "",int duration = 0);
int duration() const;
const std::string & get_current_element(int time) const;
private:
std::vector<std::pair<std::string,int> > data_;
};
class progressive_double {
public:
progressive_double(const std::string& data = "",int duration = 0);
int duration() const;
const double get_current_element(int time) const;
private:
std::vector<std::pair<std::pair<double,double>,int> > data_;
};
//a class to describe a unit's animation sequence
extern std::string grr(const char*);
class unit_frame {
public:
// constructors
unit_frame();
explicit unit_frame(const std::string& str, int begin=0,int end=1,
const std::string& highlight="1.0",
Uint32 blend_color = 0, const std::string& blend_rate = "",
const std::string& highlight="1.0",const std::string& offset="",
Uint32 blend_color = 0, const std::string& blend_rate = "0",
std::string in_halo = "",int halox = 0,int haloy = 0,
const std::string & diag ="");
explicit unit_frame(const config& cfg);
int xoffset() const { return xoffset_ ; }
std::string image() const { return image_ ;}
std::string image_diagonal() const { return image_diagonal_ ; }
const std::string halo(int current_time) const;
const std::string &halo(int current_time) const;
std::string sound() const { return sound_ ; };
int halo_x() const { return halo_x_; }
int halo_y() const { return halo_y_; }
@ -47,17 +67,19 @@ class unit_frame {
Uint32 blend_with() const { return blend_with_; }
double blend_ratio(int current_time) const;
fixed_t highlight_ratio(int current_time) const;
double offset(int current_time) const;
private:
int xoffset_;
std::string image_;
std::string image_diagonal_;
std::vector<std::pair<std::string,int> > halo_;
progressive_string halo_;
std::string sound_;
int halo_x_, halo_y_;
int begin_time_, end_time_;
Uint32 blend_with_;
std::vector<std::pair<std::pair<double,double>,int> > blend_ratio_;
std::vector<std::pair<std::pair<double,double>,int> > highlight_ratio_;
progressive_double blend_ratio_;
progressive_double highlight_ratio_;
progressive_double offset_;
};
#endif

View file

@ -865,7 +865,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
healing_animations_.push_back(healing_animation(**healing_anim));
}
if(healing_animations_.empty()) {
healing_animations_.push_back(healing_animation(unit_frame(cfg["image_healing"],0,1,"1.0",0,"",cfg["image_halo_healing"])));
healing_animations_.push_back(healing_animation(unit_frame(cfg["image_healing"],0,1,"1.0","",0,"",cfg["image_halo_healing"])));
// always have a healing animation
}
@ -893,7 +893,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
levelin_animations_.push_back(levelin_animation(**levelin_anim));
}
if(levelin_animations_.empty()) {
levelin_animations_.push_back(levelin_animation(unit_frame(image(),0,600,"1.0",display::rgb(255,255,255),"1~0:600")));
levelin_animations_.push_back(levelin_animation(unit_frame(image(),0,600,"1.0","",display::rgb(255,255,255),"1~0:600")));
// always have a levelin animation
}
expanded_cfg = unit_animation::prepare_animation(cfg,"levelout_anim");
@ -902,7 +902,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
levelout_animations_.push_back(levelout_animation(**levelout_anim));
}
if(levelout_animations_.empty()) {
levelout_animations_.push_back(levelout_animation(unit_frame(image(),0,600,"1.0",display::rgb(255,255,255),"0~1:600")));
levelout_animations_.push_back(levelout_animation(unit_frame(image(),0,600,"1.0","",display::rgb(255,255,255),"0~1:600")));
// always have a levelout animation
}
flag_rgb_ = cfg["flag_rgb"];