new low level animation engine,

should ease the macroification and tuning of animations once they are
converted (backward compatible).
This commit is contained in:
Jérémy Rosen 2006-10-15 18:19:08 +00:00
parent a351011d26
commit 5d2f781f7b
17 changed files with 412 additions and 467 deletions

View file

@ -1,5 +1,5 @@
Version 1.3-svn:
* editor
* editor
* allow maps to be loaded from scenario files and written back to them
* campaigns
* Heir to the Throne
@ -60,6 +60,8 @@ Version 1.3-svn:
* [event]s can now be written also inside [era]s (the [event]s are included
in every scenario played using that era)
* new operation for set_variable : divide
* Animations now use duration= tag instead of begin= and end= (backward
compatible)
* multiplayer game management
* client now tells the server if a game ended in victory or defeat
* configurable castle size for random map generator (patch #598, FR #3232)

View file

@ -1,20 +1,18 @@
#define DEFENSE_ANIM FRAME BASEFRAME HITSOUND
[defend]
start_time=-126
[frame]
begin=-126
end=-125
duration=1
image={BASEFRAME}
[/frame]
[frame]
begin=-125
end=-25
duration=100
image={FRAME}
[/frame]
[if]
hits=hit
[frame]
begin=-25
end=125
duration=150
image={FRAME}
sound={HITSOUND}
[/frame]
@ -22,14 +20,12 @@
[else]
hits=miss,kill
[frame]
begin=-25
end=125
duration=150
image={FRAME}
[/frame]
[/else]
[frame]
begin=125
end=126
duration=1
image={BASEFRAME}
[/frame]
[/defend]
@ -39,22 +35,20 @@
#define DEFENSE_ANIM_FILTERED FRAME BASEFRAME HITSOUND FILTER
[defend]
start_time=-126
{FILTER}
[frame]
begin=-126
end=-125
duration=1
image={BASEFRAME}
[/frame]
[frame]
begin=-125
end=-25
duration=100
image={FRAME}
[/frame]
[if]
hits=hit
[frame]
begin=-25
end=125
duration=150
image={FRAME}
sound={HITSOUND}
[/frame]
@ -62,14 +56,12 @@
[else]
hits=miss,kill
[frame]
begin=-25
end=125
duration=150
image={FRAME}
[/frame]
[/else]
[frame]
begin=125
end=126
duration=1
image={BASEFRAME}
[/frame]
[/defend]

View file

@ -1427,29 +1427,24 @@ void calculate_healing(display& disp, const gamemap& map,
if (update_display){
// This is all the pretty stuff.
bool start_time_set = false;
int start_time = 0;
int start_time = INT_MAX;
disp.scroll_to_tile(i->first.x, i->first.y, display::ONSCREEN);
disp.select_hex(i->first);
for(std::vector<unit_map::iterator>::iterator heal_anim_it = healers.begin(); heal_anim_it != healers.end(); ++heal_anim_it) {
(*heal_anim_it)->second.set_facing((*heal_anim_it)->first.get_relative_dir(i->first));
(*heal_anim_it)->second.set_healing(disp,(*heal_anim_it)->first);
if(start_time_set) {
start_time = minimum<int>(start_time,(*heal_anim_it)->second.get_animation()->get_first_frame_time());
} else {
start_time = (*heal_anim_it)->second.get_animation()->get_first_frame_time();
}
start_time = (*heal_anim_it)->second.get_animation()->get_begin_time();
}
if (healing < 0) {
i->second.set_poisoned(disp,i->first, -healing);
start_time = minimum<int>(start_time, i->second.get_animation()->get_first_frame_time());
start_time = minimum<int>(start_time, i->second.get_animation()->get_begin_time());
// FIXME
sound::play_sound("poison.ogg");
disp.float_label(i->first, lexical_cast<std::string>(-healing), 255,0,0);
} else {
i->second.set_healed(disp,i->first, healing);
start_time = minimum<int>(start_time, i->second.get_animation()->get_first_frame_time());
start_time = minimum<int>(start_time, i->second.get_animation()->get_begin_time());
sound::play_sound("heal.wav");
disp.float_label(i->first, lexical_cast<std::string>(healing), 0,255,0);
}

View file

@ -10,48 +10,46 @@
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
*/
#include "global.hpp"
//#include <string>
//#include <vector>
#include "SDL.h"
#include "animated.hpp"
#include "util.hpp"
#include "serialization/string_utils.hpp"
template<typename T, typename T_void_value>
const T animated<T,T_void_value>::void_value_ = T_void_value()();
template<typename T, typename T_void_value>
animated<T,T_void_value>::animated() :
starting_frame_time_(INT_MAX),
ending_frame_time_(INT_MIN),
animated<T,T_void_value>::animated(int start_time) :
starting_frame_time_(start_time),
does_not_change_(true),
started_(false),
no_current_frame_(true),
does_not_change_(false),
real_start_ticks_(0),
start_ticks_(0),
start_tick_(0),
cycles_(false),
acceleration_(1),
start_frame_(0)
{}
last_update_tick_(0),
current_frame_key_(start_time)
{
}
template<typename T, typename T_void_value>
animated<T,T_void_value>::animated(const std::string &cfg, const string_initializer& init):
starting_frame_time_(INT_MAX),
animated<T,T_void_value>::animated(const std::string &cfg,int start_time, const string_initializer& init):
starting_frame_time_(start_time),
does_not_change_(true),
started_(false),
no_current_frame_(true),
does_not_change_(false),
real_start_ticks_(0),
start_ticks_(0),
start_tick_(0),
cycles_(false),
acceleration_(1),
start_frame_(0)
last_update_tick_(0),
current_frame_key_(start_time)
{
std::vector<std::string> items = utils::split(cfg);
int current_time = 0;
std::vector<std::string>::const_iterator itor = items.begin();
for(; itor != items.end(); ++itor) {
const std::vector<std::string>& items = utils::split(*itor, ':');
@ -66,159 +64,110 @@ animated<T,T_void_value>::animated(const std::string &cfg, const string_initiali
time = 100;
}
frames_.push_back(frame(current_time, init(str)));
current_time += time;
add_frame(time,init(str),false);
}
starting_frame_time_ = 0;
ending_frame_time_ = current_time;
}
template<typename T, typename T_void_value>
void animated<T,T_void_value>::add_frame()
void animated<T,T_void_value>::add_frame(int duration, const T& value,bool force_change)
{
ending_frame_time_++;
frames_.push_back(frame(ending_frame_time_));
if(frames_.empty() ) {
frames_[starting_frame_time_] =
frame(duration,value);
does_not_change_=!force_change;
return;
}
typename std::map<int,frame>::const_reverse_iterator last_frame = frames_.rbegin();
does_not_change_=false;
frames_[last_frame->first +last_frame->second.duration_] =
frame(duration,value);
}
template<typename T, typename T_void_value>
void animated<T,T_void_value>::add_frame(int start)
{
frames_.push_back(frame(start));
starting_frame_time_ = minimum<int>(starting_frame_time_, start);
ending_frame_time_ = maximum<int>(ending_frame_time_, start);
}
template<typename T, typename T_void_value>
void animated<T,T_void_value>::add_frame(int start, const T& value)
{
frames_.push_back(frame(start, value));
starting_frame_time_ = minimum<int>(starting_frame_time_, start);
ending_frame_time_ = maximum<int>(ending_frame_time_, start);
}
template<typename T, typename T_void_value>
void animated<T,T_void_value>::start_animation(int start_frame, int cycles, int acceleration)
void animated<T,T_void_value>::start_animation(int start_time, bool cycles, double acceleration)
{
started_ = true;
start_frame_ = start_frame;
start_ticks_ = real_start_ticks_ = current_time_ = SDL_GetTicks() * acceleration;
last_update_tick_ = SDL_GetTicks();
start_tick_ = last_update_tick_ + ( starting_frame_time_ - start_time);
cycles_ = cycles;
current_cycle_ = 0;
acceleration_ = acceleration;
// current_frame_ = frames_.begin();
current_frame_ = 0;
no_current_frame_ = false;
if (ending_frame_time_ >= start_frame_) {
duration_ = ending_frame_time_ - start_frame_;
} else {
duration_ = 0;
}
frame_changed_ = true;
if(acceleration_ <=0) acceleration_ = 1;
current_frame_key_= frames_.begin()->first;
update_last_draw_time();
}
template<typename T, typename T_void_value>
void animated<T,T_void_value>::update_current_frame()
void animated<T,T_void_value>::update_last_draw_time()
{
// std::cerr << "--- updating frame ---\n";
last_update_tick_ = SDL_GetTicks();
if(does_not_change_)
return;
frame_changed_ = false;
// Always update current_time_, for the animation_time functions to work.
current_time_ = SDL_GetTicks() * acceleration_;
if(!started_)
// Always update last_update_tick_, for the animation_time functions to work.
if(!started_) {
return;
}
if(frames_.empty()) {
no_current_frame_ = true;
does_not_change_ = true;
return;
}
if(frames_.size() == 1 && cycles_ == INFINITE_CYCLES) {
does_not_change_ = true;
frame_changed_ = false;
if(cycles_) {
while(get_animation_time() > get_end_time()){ // cut extra time
start_tick_ +=get_end_time()/acceleration_;
current_frame_key_ =starting_frame_time_;
}
}
if (duration_ > 0) {
// Ticks is the actual time since animation started.
int ticks = current_time_ - start_ticks_;
// Handles cycle overflow
if(ticks > duration_) {
int ncycles = ticks/duration_;
current_cycle_ = minimum<int>(cycles_, current_cycle_ + ncycles);
start_ticks_ += ncycles * duration_;
ticks -= ncycles * duration_;
// current_frame_ = frames_.begin();
current_frame_ = 0;
frame_changed_ = true;
}
// Checks if the animation is finished
if(cycles_ != INFINITE_CYCLES && current_cycle_ >= cycles_) {
// If the animation is finished, the current frame is the last
// one
current_frame_ = frames_.size() - 1;
frame_changed_ = true;
// std::cerr << "Animation finished\n";
no_current_frame_ = false;
started_ = false;
return;
}
if(ticks < (frames_[current_frame_].milliseconds - start_frame_)) {
// std::cerr << "Animation not yet started\n";
frame_changed_ = true;
no_current_frame_ = true;
return;
}
// Looks for the current frame
typename std::vector<frame>::size_type i = current_frame_ + 1;
for(; i != frames_.size(); ++i) {
if(ticks < (frames_[i].milliseconds - start_frame_))
break;
current_frame_ = i;
frame_changed_ = true;
// std::cerr << "Skipping to next frame\n";
}
no_current_frame_ = false;
} else {
// If the duration is void, the animation is automatically finished.
// current_cycle_ = cycles_;
if(cycles_ != -1) {
started_ = false;
} else {
does_not_change_ = true;
}
frame_changed_ = false;
// current_frame_ = frames_.size() - 1;
// frame_changed_ = false;
// std::cerr << "Returning last frame\n";
no_current_frame_ = false;
typename std::map<int,frame>::iterator current_frame = frames_.find(current_frame_key_);
while(get_current_frame_end_time() < get_animation_time() && // catch up
get_current_frame_end_time() < get_end_time()) {// don't go after the end
current_frame++;
current_frame_key_ = current_frame->first;
}
}
template<typename T, typename T_void_value>
bool animated<T,T_void_value>::frame_changed() const
bool animated<T,T_void_value>::need_update() const
{
return frame_changed_;
if(does_not_change_) {
return false;
}
if(frames_.empty()) {
return false;
}
if(!started_) {
return false;
}
if(SDL_GetTicks() > (unsigned int)(get_current_frame_end_time()/acceleration_+start_tick_)){
return true;
}
return false;
}
template<typename T, typename T_void_value>
bool animated<T,T_void_value>::animation_would_finish() const
{
if(frames_.empty())
return true;
if(!started_)
return true;
if(!cycles_ && (SDL_GetTicks() > (unsigned int)(get_end_time()/acceleration_+start_tick_)))
return true;
return false;
}
template<typename T, typename T_void_value>
bool animated<T,T_void_value>::animation_finished() const
{
if(frames_.empty())
return true;
if(!started_)
return true;
//if(current_cycle_ == cycles_)
// return true;
if(!cycles_ && (get_animation_time() > get_end_time()))
return true;
return false;
}
@ -226,50 +175,66 @@ bool animated<T,T_void_value>::animation_finished() const
template<typename T, typename T_void_value>
int animated<T,T_void_value>::get_animation_time() const
{
if(!started_) return starting_frame_time_;
if(does_not_change_)
return SDL_GetTicks() * acceleration_ - real_start_ticks_ + start_frame_;
if(!started_ ) return starting_frame_time_;
return current_time_ - real_start_ticks_ + start_frame_;
}
template<typename T, typename T_void_value>
int animated<T,T_void_value>::get_cycle_time() const
{
return current_time_ - start_ticks_ + start_frame_;
return ((double)(last_update_tick_ - start_tick_)*acceleration_)+starting_frame_time_;
}
template<typename T, typename T_void_value>
const T& animated<T,T_void_value>::get_current_frame() const
{
if(no_current_frame_ == true)
if(frames_.empty() )
return void_value_;
const frame& cur = frames_[current_frame_];
if(!cur.has_value)
return void_value_;
return cur.value;
return frames_.find(current_frame_key_)->second.value_;
}
template<typename T, typename T_void_value>
const int animated<T,T_void_value>::get_current_frame_begin_time() const
{
if(frames_.empty() )
return starting_frame_time_;
return frames_.find(current_frame_key_)->first;
}
template<typename T, typename T_void_value>
const int animated<T,T_void_value>::get_current_frame_end_time() const
{
if(frames_.empty() )
return starting_frame_time_;
return get_current_frame_begin_time() +get_current_frame_duration();
}
template<typename T, typename T_void_value>
const int animated<T,T_void_value>::get_current_frame_duration() const
{
if(frames_.empty() )
return 0;
return frames_.find(current_frame_key_)->second.duration_;
}
template<typename T, typename T_void_value>
const int animated<T,T_void_value>::get_current_frame_time() const
{
if(frames_.empty() )
return 0;
return maximum<int>(get_current_frame_begin_time(),get_animation_time() - get_current_frame_begin_time());
}
template<typename T, typename T_void_value>
const T& animated<T,T_void_value>::get_first_frame() const
{
typename std::vector<frame>::const_iterator frame_;
for(frame_ = frames_.begin() ; frame_ != frames_.end(); frame_++ ) {
if(frame_->has_value)
return frame_->value;
}
return void_value_;
if(frames_.empty() )
return void_value_;
return frames_.begin()->second.value_;
}
template<typename T, typename T_void_value>
const T& animated<T,T_void_value>::get_last_frame() const
{
typename std::vector<frame>::const_reverse_iterator frame_;
for(frame_ = frames_.rbegin() ; frame_ != frames_.rend(); frame_++ ) {
if(frame_->has_value)
return frame_->value;
}
return void_value_;
if(frames_.empty() )
return void_value_;
typename std::map<int,frame>::const_reverse_iterator last_frame = frames_.rbegin();
return last_frame->second.value_;
}
template<typename T, typename T_void_value>
@ -279,24 +244,20 @@ int animated<T,T_void_value>::get_frames_count() const
}
template<typename T, typename T_void_value>
int animated<T,T_void_value>::get_first_frame_time() const
int animated<T,T_void_value>::get_begin_time() const
{
if (starting_frame_time_ != INT_MAX && starting_frame_time_ != INT_MIN)
return starting_frame_time_;
return 0;
return starting_frame_time_;
}
template<typename T, typename T_void_value>
int animated<T,T_void_value>::get_last_frame_time() const
int animated<T,T_void_value>::get_end_time() const
{
if (ending_frame_time_ != INT_MAX && ending_frame_time_ != INT_MIN)
return ending_frame_time_;
return 0;
if(frames_.empty())
return starting_frame_time_;
typename std::map<int,frame>::const_reverse_iterator last_frame = frames_.rbegin();
return (last_frame->first +last_frame->second.duration_);
}
// Force compilation of the following template instantiations
#include "unit_frame.hpp"

View file

@ -15,7 +15,7 @@
#define ANIMATED_IMAGE_H_INCLUDED
#include <string>
#include <vector>
#include <map>
template<typename T>
class void_value
@ -35,7 +35,7 @@ public:
virtual ~string_initializer(){};
};
animated();
animated(int start_time=0);
virtual ~animated(){};
//if T can be constructed from a string, you may use this constructor
@ -43,78 +43,69 @@ public:
//if T cannot, you may provide a custom (subclassed) string_initializer
//to do the job
animated(const std::string &cfg, const string_initializer& init=string_initializer());
animated(const std::string &cfg, int start_time = 0, const string_initializer& init=string_initializer());
// Adds a void frame at the end
void add_frame();
// Adds a void frame
void add_frame(int start);
// Adds a frame
void add_frame(int start, const T& value);
void add_frame(int duration, const T& value,bool force_change =false);
//Starts an animation cycle. The first frame of the animation to start
//may be set to any value
enum { INFINITE_CYCLES = -1 };
void start_animation(int start_time=0, int cycles=1, int acceleration=1);
void start_animation(int start_time=0, bool cycles=false, double acceleration=1);
int get_first_frame_time() const;
int get_last_frame_time() const;
int get_begin_time() const;
int get_end_time() const;
//inlined for performance
void update_current_frame();
bool frame_changed() const;
void update_last_draw_time();
bool need_update() const;
//True if the current animation was finished
bool animation_finished() const;
bool animation_would_finish() const;
int get_animation_time() const;
int get_cycle_time() const;
const T& get_current_frame() const;
const int get_current_frame_begin_time() const;
const int get_current_frame_end_time() const;
const int get_current_frame_duration() const;
const int get_current_frame_time() const;
const T& get_first_frame() const;
const T& get_last_frame() const;
int get_frames_count() const;
const bool does_not_change() const {return does_not_change_;}
protected:
int starting_frame_time_;
private:
struct frame
{
frame(int milliseconds) :
milliseconds(milliseconds), has_value(false)
{};
frame(int milliseconds, const T& value) :
milliseconds(milliseconds), has_value(true), value(value)
frame(int duration , const T& value) :
duration_(duration),value_(value)
{};
frame():
duration_(0),value_(void_value_)
{};
// Represents the timestamp of the frame start
int milliseconds;
bool has_value;
T value;
int duration_;
T value_;
};
static const T void_value_;
int starting_frame_time_;
int ending_frame_time_;
bool started_;
bool no_current_frame_;
bool does_not_change_; // optimization for 1-frame permanent animations
bool started_;
std::map<int,frame> frames_;
int real_start_ticks_;
int start_ticks_;
int current_cycle_;
int current_time_;
int cycles_;
int acceleration_;
bool frame_changed_;
int start_frame_;
int duration_;
typename std::vector<frame>::size_type current_frame_;
//these are only valid when anim is started
int start_tick_; // time at which we started
bool cycles_;
double acceleration_;
int last_update_tick_;
int current_frame_key_;
std::vector<frame> frames_;
};
#endif

View file

@ -189,16 +189,16 @@ bool terrain_builder::update_animation(const gamemap::location &loc)
imagelist::iterator itor = bg.begin();
for(; itor != bg.end(); ++itor) {
itor->update_current_frame();
if(itor->frame_changed())
if(itor->need_update())
changed = true;
itor->update_last_draw_time();
}
itor = fg.begin();
for(; itor != fg.end(); ++itor) {
itor->update_current_frame();
if(itor->frame_changed())
if(itor->need_update())
changed = true;
itor->update_last_draw_time();
}
return changed;
@ -215,7 +215,7 @@ void terrain_builder::rebuild_terrain(const gamemap::location &loc)
const std::string filename =
map_.get_terrain_info(map_.get_terrain(loc)).symbol_image();
animated<image::locator> img_loc("terrain/" + filename + ".png");
img_loc.start_animation(0, animated<image::locator>::INFINITE_CYCLES);
img_loc.start_animation(0, true);
btile.images_background.push_back(img_loc);
}
}
@ -280,12 +280,12 @@ bool terrain_builder::start_animation(building_rule &rule)
initializer = locator_string_initializer(constraint->second.loc);
}
animated<image::locator> th(variant->second.image_string,
animated<image::locator> th(variant->second.image_string,0,
initializer);
variant->second.image = th;
variant->second.image.start_animation(0, animated<image::locator>::INFINITE_CYCLES);
variant->second.image.update_current_frame();
variant->second.image.start_animation(0, true);
variant->second.image.update_last_draw_time();
}
}
}

View file

@ -120,29 +120,26 @@ display::display(unit_map& units, CVideo& video, const gamemap& map,
animated<image::locator> temp_anim;
std::vector<std::string> items = utils::split(flag);
int current_time = 0;
std::vector<std::string>::const_iterator itor = items.begin();
for(; itor != items.end(); ++itor) {
const std::vector<std::string>& items = utils::split(*itor, ':');
std::string str;
int time;
const std::vector<std::string>& items = utils::split(*itor, ':');
std::string str;
int time;
if(items.size() > 1) {
str = items.front();
time = atoi(items.back().c_str());
} else {
str = *itor;
time = 100;
}
if(items.size() > 1) {
str = items.front();
time = atoi(items.back().c_str());
} else {
str = *itor;
time = 100;
}
image::locator flag_image(str, new_rgb, old_rgb);
temp_anim.add_frame(current_time, flag_image);
current_time += time;
image::locator flag_image(str, new_rgb, old_rgb);
temp_anim.add_frame(time, flag_image);
}
temp_anim.add_frame(current_time);
flags_.push_back(temp_anim);
flags_.back().start_animation(rand()%flags_.back().get_frames_count(), animated<image::locator>::INFINITE_CYCLES);
flags_.back().start_animation(rand()%flags_.back().get_end_time(), true);
}
//clear the screen contents
@ -869,6 +866,9 @@ void display::draw(bool update,bool force)
unit_invals.insert(*it);
}
draw_tile(*it, clip_rect);
if(map_.is_village(*it) && player_teams::village_owner(*it) != -1) {
flags_[player_teams::village_owner(*it)].update_last_draw_time();
}
}
@ -2060,8 +2060,7 @@ void display::invalidate_animations()
get_visible_hex_bounds(topleft, bottomright);
for(size_t i = 0; i < flags_.size(); ++i) {
flags_[i].update_current_frame();
if(flags_[i].frame_changed()) {
if(flags_[i].need_update()) {
animate_flags = true;
}
}
@ -2076,14 +2075,14 @@ void display::invalidate_animations()
}
unit_map::iterator unit;
for(unit=units_.begin() ; unit != units_.end() ; unit++) {
unit->second.refresh(*this,unit->first);
if (unit->second.get_animation() && !unit->second.get_animation()->does_not_change())
if (unit->second.get_animation() && unit->second.get_animation()->need_update())
invalidate(unit->first);
unit->second.refresh(*this,unit->first);
}
if (temp_unit_ ) {
temp_unit_->refresh(*this, temp_unit_loc_);
if (temp_unit_->get_animation() && !temp_unit_->get_animation()->does_not_change())
if (temp_unit_->get_animation() && temp_unit_->get_animation()->need_update())
invalidate(temp_unit_loc_);
temp_unit_->refresh(*this, temp_unit_loc_);
}

View file

@ -35,7 +35,7 @@ display* disp = NULL;
class effect
{
public:
effect(int xpos, int ypos, const std::string& img, ORIENTATION orientation, int lifetime);
effect(int xpos, int ypos, const std::string& img, ORIENTATION orientation,bool infinite);
void set_location(int x, int y);
@ -66,7 +66,7 @@ int halo_id = 1;
bool hide_halo = false;
effect::effect(int xpos, int ypos, const std::string& img, ORIENTATION orientation, int lifetime)
effect::effect(int xpos, int ypos, const std::string& img, ORIENTATION orientation,bool infinite)
: images_(img), orientation_(orientation), origx_(xpos), origy_(ypos), x_(xpos), y_(ypos),
origzoom_(disp->zoom()), zoom_(disp->zoom()), surf_(NULL), buffer_(NULL), rect_(empty_rect)
{
@ -75,10 +75,10 @@ effect::effect(int xpos, int ypos, const std::string& img, ORIENTATION orientati
set_location(xpos,ypos);
images_.start_animation(0, lifetime);
images_.start_animation(0,infinite);
if(!images_.animation_finished()) {
images_.update_current_frame();
images_.update_last_draw_time();
}
current_image_ = "";
@ -131,7 +131,7 @@ void effect::render()
return;
}
images_.update_current_frame();
images_.update_last_draw_time();
const std::string& img = current_image();
if(surf_ == NULL || zoom_ != disp->zoom() || current_image_ != img) {
current_image_ = img;
@ -218,10 +218,10 @@ halo_hider::~halo_hider()
unrender();
}
int add(int x, int y, const std::string& image, ORIENTATION orientation, int lifetime_cycles)
int add(int x, int y, const std::string& image, ORIENTATION orientation, bool infinite)
{
const int id = halo_id++;
haloes.insert(std::pair<int,effect>(id,effect(x,y,image,orientation,lifetime_cycles)));
haloes.insert(std::pair<int,effect>(id,effect(x,y,image,orientation,infinite)));
return id;
}

View file

@ -46,7 +46,7 @@ enum ORIENTATION { NORMAL, HREVERSE, VREVERSE, HVREVERSE };
///centered on (x,y)
///returns the handle to the halo object
///0 is the invalid handle
int add(int x, int y, const std::string& image, ORIENTATION orientation=NORMAL, int lifetime_cycles=-1);
int add(int x, int y, const std::string& image, ORIENTATION orientation=NORMAL, bool infinite=true);
///function to set the position of an existing haloing
///effect, according to its handle

View file

@ -445,8 +445,6 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
flag = current_team.flag();
}
//must recolor flag image
animated<image::locator> temp_anim;
// remove animation stuff we don't care about
const std::vector<std::string> items = utils::split(flag);

View file

@ -1316,7 +1316,7 @@ void unit::read(const config& cfg)
defensive_animations_.push_back(defensive_animation(**d));
}
if(defensive_animations_.empty()) {
defensive_animations_.push_back(defensive_animation(unit_frame(absolute_image(),-150,150)));
defensive_animations_.push_back(defensive_animation(-150,unit_frame(absolute_image(),300)));
// always have a defensive animation
}
@ -1324,7 +1324,7 @@ void unit::read(const config& cfg)
teleport_animations_.push_back(unit_animation(**t));
}
if(teleport_animations_.empty()) {
teleport_animations_.push_back(unit_animation(unit_frame(absolute_image(),-20,20)));
teleport_animations_.push_back(unit_animation(-20,unit_frame(absolute_image(),40)));
// always have a teleport animation
}
@ -1336,7 +1336,7 @@ void unit::read(const config& cfg)
death_animations_.push_back(death_animation(**death));
}
if(death_animations_.empty()) {
death_animations_.push_back(death_animation(unit_frame(absolute_image(),0,10)));
death_animations_.push_back(death_animation(0,unit_frame(absolute_image(),10)));
// always have a death animation
}
@ -1344,7 +1344,7 @@ void unit::read(const config& cfg)
movement_animations_.push_back(movement_animation(**movement_anim));
}
if(movement_animations_.empty()) {
movement_animations_.push_back(movement_animation(unit_frame(absolute_image(),0,150)));
movement_animations_.push_back(movement_animation(0,unit_frame(absolute_image(),150)));
// always have a movement animation
}
@ -1352,7 +1352,7 @@ void unit::read(const config& cfg)
standing_animations_.push_back(standing_animation(**standing_anim));
}
if(standing_animations_.empty()) {
standing_animations_.push_back(standing_animation(unit_frame(absolute_image(),0,0)));
standing_animations_.push_back(standing_animation(0,unit_frame(absolute_image(),0)));
// always have a standing animation
}
@ -1360,7 +1360,7 @@ void unit::read(const config& cfg)
leading_animations_.push_back(leading_animation(**leading_anim));
}
if(leading_animations_.empty()) {
leading_animations_.push_back(leading_animation(unit_frame(absolute_image(),0,150)));
leading_animations_.push_back(leading_animation(0,unit_frame(absolute_image(),150)));
// always have a leading animation
}
@ -1368,7 +1368,7 @@ void unit::read(const config& cfg)
healing_animations_.push_back(healing_animation(**healing_anim));
}
if(healing_animations_.empty()) {
healing_animations_.push_back(healing_animation(unit_frame(image_healing(),0,150,
healing_animations_.push_back(healing_animation(0,unit_frame(image_healing(),150,
"1.0","",0,"",image_halo_healing(),0,0)));
// always have a healing animation
}
@ -1377,7 +1377,7 @@ void unit::read(const config& cfg)
recruit_animations_.push_back(recruit_animation(**recruit_anim));
}
if(recruit_animations_.empty()) {
recruit_animations_.push_back(recruit_animation(unit_frame(absolute_image(),0,600,"0~1:600")));
recruit_animations_.push_back(recruit_animation(0,unit_frame(absolute_image(),600,"0~1:600")));
// always have a recruit animation
}
@ -1385,7 +1385,7 @@ void unit::read(const config& cfg)
idle_animations_.push_back(idle_animation(**idle_anim));
}
if(idle_animations_.empty()) {
idle_animations_.push_back(idle_animation(unit_frame(absolute_image(),0,1)));
idle_animations_.push_back(idle_animation(0,unit_frame(absolute_image(),1)));
// always have a idle animation
}
@ -1393,7 +1393,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(0,unit_frame(absolute_image(),600,"1.0","",display::rgb(255,255,255),"1~0:600")));
// always have a levelin animation
}
@ -1401,7 +1401,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(0,unit_frame(absolute_image(),600,"1.0","",display::rgb(255,255,255),"0~1:600")));
// always have a levelout animation
}
@ -1582,7 +1582,6 @@ const surface unit::still_image() const
void unit::refresh(const display& disp,const gamemap::location& loc)
{
if(state_ == STATE_IDLING && anim_ && anim_->animation_finished()) set_standing(disp, loc);
if(anim_) anim_->update_current_frame();
if(state_ != STATE_STANDING || SDL_GetTicks() < next_idling) return;
set_idling(disp, loc);
}
@ -1598,9 +1597,8 @@ void unit::set_standing(const display &disp,const gamemap::location& loc, bool w
anim_ = NULL;
}
anim_ = new standing_animation(stand_animation(disp,loc));
anim_->start_animation(anim_->get_first_frame_time(),unit_animation::INFINITE_CYCLES,disp.turbo_speed());
frame_begin_time = anim_->get_first_frame_time() -1;
anim_->update_current_frame();
anim_->start_animation(anim_->get_begin_time(),true,disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
next_idling= SDL_GetTicks() +30000 +rand()%10000;
}
void unit::set_defending(const display &disp,const gamemap::location& loc, int damage,const attack_type* attack,const attack_type* secondary_attack,int swing_num)
@ -1622,16 +1620,12 @@ void unit::set_defending(const display &disp,const gamemap::location& loc, int d
anim_ = new defensive_animation(defend_animation(disp,loc,hit_type,attack,secondary_attack,swing_num,damage));
// add a blink on damage effect
int anim_time = anim_->get_last_frame_time();
const image::locator 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_time+=100;
anim_->add_frame(100,unit_frame(my_image,100,"1.0","",display::rgb(255,0,0),"0.5:50,0.0:50"));
}
anim_->add_frame(anim_time);
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_extra_anim(const display &disp,const gamemap::location& loc, std::string flag)
@ -1647,9 +1641,8 @@ void unit::set_extra_anim(const display &disp,const gamemap::location& loc, std:
return;
}
anim_ = new unit_animation(*(extra_animation(disp,loc,flag)));
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
const unit_animation & unit::set_attacking(const display &disp,const gamemap::location& loc,int damage,const attack_type& type,const attack_type* secondary_attack,int swing_num)
@ -1669,9 +1662,8 @@ const unit_animation & unit::set_attacking(const display &disp,const gamemap::lo
hit_type = fighting_animation::MISS;
}
anim_ = new attack_animation(type.animation(disp,loc,this,hit_type,secondary_attack,swing_num,damage));
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
return ((attack_animation*)anim_)->get_missile_anim();
}
void unit::set_leading(const display &disp,const gamemap::location& loc)
@ -1683,9 +1675,8 @@ void unit::set_leading(const display &disp,const gamemap::location& loc)
anim_ = NULL;
}
anim_ = new leading_animation(lead_animation(disp,loc));
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_leveling_in(const display &disp,const gamemap::location& loc)
{
@ -1696,9 +1687,8 @@ void unit::set_leveling_in(const display &disp,const gamemap::location& loc)
anim_ = NULL;
}
anim_ = new levelin_animation(levelingin_animation(disp,loc));
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_leveling_out(const display &disp,const gamemap::location& loc)
{
@ -1709,9 +1699,8 @@ void unit::set_leveling_out(const display &disp,const gamemap::location& loc)
anim_ = NULL;
}
anim_ = new levelout_animation(levelingout_animation(disp,loc));
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_recruited(const display &disp,const gamemap::location& loc)
{
@ -1723,9 +1712,8 @@ void unit::set_recruited(const display &disp,const gamemap::location& loc)
}
anim_ = new recruit_animation(recruiting_animation(disp,loc));
// add a fade in effect
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_healed(const display &disp,const gamemap::location& /*loc*/, int /*healing*/)
{
@ -1735,10 +1723,9 @@ 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_->start_animation(anim_->get_first_frame_time(), 1, disp.turbo_speed());
frame_begin_time = anim_->get_first_frame_time() -1;
anim_->update_current_frame();
anim_ = new unit_animation(0,unit_frame(absolute_image(),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_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_poisoned(const display &disp,const gamemap::location& /*loc*/, int /*damage*/)
{
@ -1748,10 +1735,9 @@ 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_->start_animation(anim_->get_first_frame_time(), 1, disp.turbo_speed());
frame_begin_time = anim_->get_first_frame_time() -1;
anim_->update_current_frame();
anim_ = new unit_animation(0,unit_frame(absolute_image(),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_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_teleporting(const display &disp,const gamemap::location& loc)
@ -1763,9 +1749,8 @@ void unit::set_teleporting(const display &disp,const gamemap::location& loc)
anim_ = NULL;
}
anim_ = new unit_animation(teleport_animation(disp,loc));
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();
anim_->start_animation(anim_->get_begin_time(),false,disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_dying(const display &disp,const gamemap::location& loc,const attack_type* attack,const attack_type* secondary_attack)
@ -1778,12 +1763,9 @@ void unit::set_dying(const display &disp,const gamemap::location& loc,const atta
}
anim_ = new death_animation(die_animation(disp,loc,fighting_animation::KILL,attack,secondary_attack));
image::locator tmp_image = anim_->get_last_frame().image();
int anim_time =anim_->get_last_frame_time();
anim_->add_frame(0,unit_frame(tmp_image,anim_time,anim_time+600,"1~0:600"));
anim_->add_frame(anim_time+600);
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();
anim_->add_frame(600,unit_frame(tmp_image,600,"1~0:600"));
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_healing(const display &disp,const gamemap::location& loc)
{
@ -1794,9 +1776,8 @@ void unit::set_healing(const display &disp,const gamemap::location& loc)
anim_ = NULL;
}
anim_ = new healing_animation(heal_animation(disp,loc));
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::set_walking(const display &disp,const gamemap::location& loc)
@ -1812,8 +1793,8 @@ void unit::set_walking(const display &disp,const gamemap::location& loc)
anim_ = NULL;
}
anim_ = new movement_animation(move_animation(disp,loc));
anim_->start_animation(anim_->get_first_frame_time(), 1, disp.turbo_speed());
frame_begin_time = anim_->get_first_frame_time() -1;
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
@ -1826,15 +1807,14 @@ void unit::set_idling(const display &disp,const gamemap::location& loc)
anim_ = NULL;
}
anim_ = new idle_animation(idling_animation(disp,loc));
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();
anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed());
frame_begin_time = anim_->get_begin_time() -1;
}
void unit::restart_animation(const display& disp,int start_time) {
if(!anim_) return;
anim_->start_animation(start_time,1,disp.turbo_speed());
anim_->start_animation(start_time,false,disp.turbo_speed());
frame_begin_time = start_time -1;
}
@ -1869,17 +1849,17 @@ void unit::redraw_unit(display& disp,gamemap::location hex)
unit_frame current_frame;
if(anim_->animation_finished()) current_frame = anim_->get_last_frame();
else if(anim_->get_first_frame_time() > anim_->get_animation_time()) current_frame = anim_->get_first_frame();
else if(anim_->get_begin_time() > anim_->get_animation_time()) current_frame = anim_->get_first_frame();
else current_frame = anim_->get_current_frame();
image::locator loc;
loc = current_frame.image();
double tmp_offset = current_frame.offset(anim_->get_animation_time());
double tmp_offset = current_frame.offset(anim_->get_current_frame_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(frame_begin_time != anim_->get_current_frame_begin_time()) {
frame_begin_time = anim_->get_current_frame_begin_time();
if(!current_frame.sound().empty()) {
sound::play_sound(current_frame.sound());
}
@ -1887,18 +1867,18 @@ void unit::redraw_unit(display& disp,gamemap::location hex)
}
if(unit_anim_halo_) halo::remove(unit_anim_halo_);
unit_anim_halo_ = 0;
if(!current_frame.halo(anim_->get_animation_time()).empty()) {
if(!current_frame.halo(anim_->get_current_frame_time()).empty()) {
if(facing_ == gamemap::location::NORTH_WEST || facing_ == gamemap::location::SOUTH_WEST) {
const int d = disp.hex_size() / 2;
unit_anim_halo_ = halo::add(x+d-static_cast<int>(current_frame.halo_x(anim_->get_animation_time())*disp.zoom()),
y+d+static_cast<int>(current_frame.halo_y(anim_->get_animation_time())*disp.zoom()),
current_frame.halo(anim_->get_animation_time()));
unit_anim_halo_ = halo::add(x+d-static_cast<int>(current_frame.halo_x(anim_->get_current_frame_time())*disp.zoom()),
y+d+static_cast<int>(current_frame.halo_y(anim_->get_current_frame_time())*disp.zoom()),
current_frame.halo(anim_->get_current_frame_time()));
} else {
const int d = disp.hex_size() / 2;
unit_anim_halo_ = halo::add(x+d+static_cast<int>(current_frame.halo_x(anim_->get_animation_time())*disp.zoom()),
y+d+static_cast<int>(current_frame.halo_y(anim_->get_animation_time())*disp.zoom()),
current_frame.halo(anim_->get_animation_time()),
unit_anim_halo_ = halo::add(x+d+static_cast<int>(current_frame.halo_x(anim_->get_current_frame_time())*disp.zoom()),
y+d+static_cast<int>(current_frame.halo_y(anim_->get_current_frame_time())*disp.zoom()),
current_frame.halo(anim_->get_current_frame_time()),
halo::HREVERSE);
}
}
@ -1922,9 +1902,9 @@ void unit::redraw_unit(display& disp,gamemap::location hex)
}
Uint32 blend_with = current_frame.blend_with();
double blend_ratio = current_frame.blend_ratio(anim_->get_animation_time());
double blend_ratio = current_frame.blend_ratio(anim_->get_current_frame_time());
if(blend_ratio == 0) { blend_with = disp.rgb(0,0,0); }
fixed_t highlight_ratio = minimum<fixed_t>(alpha(),current_frame.highlight_ratio(anim_->get_animation_time()));
fixed_t highlight_ratio = minimum<fixed_t>(alpha(),current_frame.highlight_ratio(anim_->get_current_frame_time()));
if(invisible(hex,disp.get_units(),disp.get_teams()) &&
highlight_ratio > ftofxp(0.5)) {
highlight_ratio = ftofxp(0.5);
@ -2029,6 +2009,7 @@ void unit::redraw_unit(display& disp,gamemap::location hex)
}
}
refreshing_ = false;
anim_->update_last_draw_time();
}
gamemap::location::DIRECTION unit::facing() const
@ -2063,8 +2044,8 @@ std::set<gamemap::location> unit::overlaps(const gamemap::location &loc) const
break;
}
//very early calls, anim not initialized yet
if(!anim_) return over;
double tmp_offset = anim_->get_current_frame().offset(anim_->get_animation_time());
double tmp_offset=offset_;
if(anim_)tmp_offset= anim_->get_current_frame().offset(anim_->get_animation_time());
if(tmp_offset == -20.0) tmp_offset = offset_;
// invalidate adj neighbours
if(tmp_offset > 0) {

View file

@ -90,22 +90,23 @@ config unit_animation::prepare_animation(const config &cfg,const std::string ani
return expanded_animations;
}
unit_animation::unit_animation(const unit_frame & frame )
unit_animation::unit_animation(int start_time,const unit_frame & frame ):animated<unit_frame>(start_time)
{
add_frame(0,frame);
if(frame.end_time() != frame.begin_time()) add_frame(frame.end_time());
add_frame(frame.duration(),frame,!frame.does_not_change());
}
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);
if(cfg["start_time"].empty() &&range.first != range.second) {
starting_frame_time_ = atoi((**range.first)["begin"].c_str());
} else {
starting_frame_time_ = atoi(cfg["start_time"].c_str());
}
for(; range.first != range.second; ++range.first) {
unit_frame tmp_frame(**range.first);
add_frame(tmp_frame.duration(),tmp_frame,!tmp_frame.does_not_change());
}
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) {

View file

@ -34,7 +34,7 @@ class unit_animation:public animated<unit_frame>
unit_animation(){};
explicit unit_animation(const config& cfg,const std::string frame_string ="frame");
explicit unit_animation(const unit_frame &frame);
explicit unit_animation(int start_time,const unit_frame &frame);
int matches(const display &disp,const gamemap::location& loc,const unit* my_unit) const;
private:
@ -53,8 +53,8 @@ class fighting_animation:public unit_animation
typedef enum { HIT, MISS, KILL} hit_type;
explicit fighting_animation(const config& cfg);
explicit fighting_animation(const unit_frame &frame):
unit_animation(frame) {};
explicit fighting_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame) {};
int matches(const display &disp,const gamemap::location& loc,const unit* my_unit,hit_type hit,const attack_type* attack,const attack_type* second_attack, int swing_num,int damage) const;
private:
@ -69,7 +69,7 @@ class defensive_animation:public fighting_animation
{
public:
explicit defensive_animation(const config& cfg):fighting_animation(cfg){};
explicit defensive_animation(const unit_frame &frame):fighting_animation(frame){};
explicit defensive_animation(int start_time,const unit_frame &frame):fighting_animation(start_time,frame){};
};
@ -77,7 +77,7 @@ class death_animation:public fighting_animation
{
public:
explicit death_animation(const config& cfg):fighting_animation(cfg){};
explicit death_animation(const unit_frame &frame):fighting_animation(frame) {};
explicit death_animation(int start_time,const unit_frame &frame):fighting_animation(start_time,frame) {};
private:
};
@ -85,7 +85,7 @@ class attack_animation: public fighting_animation
{
public:
explicit attack_animation(const config& cfg):fighting_animation(cfg),missile_anim(cfg,"missile_frame"){};
explicit attack_animation(const unit_frame &frame):fighting_animation(frame) {};
explicit attack_animation(int start_time,const unit_frame &frame):fighting_animation(start_time,frame) {};
const unit_animation &get_missile_anim() {return missile_anim;}
private:
unit_animation missile_anim;
@ -96,8 +96,8 @@ class movement_animation:public unit_animation
{
public:
explicit movement_animation(const config& cfg):unit_animation(cfg){};
explicit movement_animation(const unit_frame &frame):
unit_animation(frame){};
explicit movement_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame){};
private:
};
@ -106,8 +106,8 @@ class standing_animation:public unit_animation
{
public:
explicit standing_animation(const config& cfg):unit_animation(cfg){};
explicit standing_animation(const unit_frame &frame):
unit_animation(frame){};
explicit standing_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame){};
private:
};
@ -116,8 +116,8 @@ class leading_animation:public unit_animation
{
public:
explicit leading_animation(const config& cfg):unit_animation(cfg){};
explicit leading_animation(const unit_frame &frame):
unit_animation(frame){};
explicit leading_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame){};
private:
};
@ -126,8 +126,8 @@ class healing_animation:public unit_animation
{
public:
explicit healing_animation(const config& cfg):unit_animation(cfg){};
explicit healing_animation(const unit_frame &frame):
unit_animation(frame){};
explicit healing_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame){};
private:
};
@ -136,8 +136,8 @@ class recruit_animation:public unit_animation
{
public:
explicit recruit_animation(const config& cfg):unit_animation(cfg){};
explicit recruit_animation(const unit_frame &frame):
unit_animation(frame){};
explicit recruit_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame){};
private:
};
@ -146,8 +146,8 @@ class idle_animation:public unit_animation
{
public:
explicit idle_animation(const config& cfg):unit_animation(cfg){};
explicit idle_animation(const unit_frame &frame):
unit_animation(frame){};
explicit idle_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame){};
private:
};
@ -156,8 +156,8 @@ class levelin_animation:public unit_animation
{
public:
explicit levelin_animation(const config& cfg):unit_animation(cfg){};
explicit levelin_animation(const unit_frame &frame):
unit_animation(frame){};
explicit levelin_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame){};
private:
};
@ -166,8 +166,8 @@ class levelout_animation:public unit_animation
{
public:
explicit levelout_animation(const config& cfg):unit_animation(cfg){};
explicit levelout_animation(const unit_frame &frame):
unit_animation(frame){};
explicit levelout_animation(int start_time,const unit_frame &frame):
unit_animation(start_time,frame){};
private:
};

View file

@ -269,10 +269,10 @@ bool unit_attack_ranged(display& disp, unit_map& units,
defender.set_defending(disp,b,damage,&attack,secondary_attack,swing);
// min of attacker, defender, missile and -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);
start_time = minimum<int>(start_time,defender.get_animation()->get_begin_time());
start_time = minimum<int>(start_time,missile_animation.get_begin_time());
start_time = minimum<int>(start_time,attacker.get_animation()->get_begin_time());
missile_animation.start_animation(start_time,false,acceleration);
defender.restart_animation(disp,start_time);
attacker.restart_animation(disp,start_time);
animation_time = defender.get_animation()->get_animation_time();
@ -286,14 +286,10 @@ bool unit_attack_ranged(display& disp, unit_map& units,
(leader_loc.valid() && leader->second.state() != unit::STATE_STANDING))
){
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());
else pos= 1.0-pos;*/
double pos = missile_frame.offset(animation_time);
double pos = missile_frame.offset(missile_animation.get_current_frame_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());
pos = double(animation_time -missile_animation.get_begin_time())/
double(missile_animation.get_end_time()-missile_animation.get_begin_time());
}
disp.invalidate(b);
disp.invalidate(a);
@ -302,8 +298,8 @@ 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_first_frame_time() &&
animation_time < missile_animation.get_last_frame_time() &&
if(animation_time > missile_animation.get_begin_time() &&
animation_time < missile_animation.get_end_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);
@ -315,16 +311,16 @@ bool unit_attack_ranged(display& disp, unit_map& units,
} else {
missile_image = missile_frame.image_diagonal();
}
if(!missile_frame.halo(animation_time).empty()) {
if(!missile_frame.halo(missile_animation.get_current_frame_time()).empty()) {
if(attack_ori != gamemap::location::SOUTH_WEST && attack_ori != gamemap::location::NORTH_WEST) {
missile_halo = halo::add(posx+d+missile_frame.halo_x(animation_time),
posy+d+missile_frame.halo_y(animation_time),
missile_frame.halo(animation_time),
missile_halo = halo::add(posx+d+missile_frame.halo_x(missile_animation.get_current_frame_time()),
posy+d+missile_frame.halo_y(missile_animation.get_current_frame_time()),
missile_frame.halo(missile_animation.get_current_frame_time()),
orientation);
} else {
missile_halo = halo::add(posx+d-missile_frame.halo_x(animation_time),
posy+d+missile_frame.halo_y(animation_time),
missile_frame.halo(animation_time),
missile_halo = halo::add(posx+d-missile_frame.halo_x(missile_animation.get_current_frame_time()),
posy+d+missile_frame.halo_y(missile_animation.get_current_frame_time()),
missile_frame.halo(missile_animation.get_current_frame_time()),
orientation);
}
}
@ -351,10 +347,10 @@ bool unit_attack_ranged(display& disp, unit_map& units,
if(leader_loc.valid() && leader->second.get_animation()->animation_finished() ) {
leader->second.set_standing(disp,leader_loc,true);
}
missile_animation.update_last_draw_time();
disp.delay(10);
// we use missile animation because it's the only one not reseted in the middle to go to standing
animation_time = missile_animation.get_animation_time();
missile_animation.update_current_frame();
}
// make sure get hit sound is always played and labels always displayed
if(damage > 0 && !hide && !sound_played) {
@ -419,11 +415,11 @@ bool unit_attack(display& disp, unit_map& units,
attacker.set_attacking(disp,a,damage,attack,secondary_attack,swing);
start_time=minimum<int>(start_time,attacker.get_animation()->get_first_frame_time());
end_time=attacker.get_animation()->get_last_frame_time();
start_time=minimum<int>(start_time,attacker.get_animation()->get_begin_time());
end_time=attacker.get_animation()->get_end_time();
defender.set_defending(disp,b,damage,&attack, secondary_attack, swing);
start_time=minimum<int>(start_time,defender.get_animation()->get_first_frame_time());
start_time=minimum<int>(start_time,defender.get_animation()->get_begin_time());
const gamemap::location leader_loc = under_leadership(units,a);
@ -434,7 +430,7 @@ bool unit_attack(display& disp, unit_map& units,
wassert(leader != units.end());
leader->second.set_facing(leader_loc.get_relative_dir(a));
leader->second.set_leading(disp,leader_loc);
start_time=minimum<int>(start_time,leader->second.get_animation()->get_first_frame_time());
start_time=minimum<int>(start_time,leader->second.get_animation()->get_begin_time());
}
@ -463,12 +459,12 @@ bool unit_attack(display& disp, unit_map& units,
){
double pos = 0.0;
if(animation_time < attacker.get_animation()->get_first_frame_time()) {
if(animation_time < attacker.get_animation()->get_begin_time()) {
pos = 0.0;
} else if( animation_time > 0) {
pos = (1.0-double(animation_time)/double(end_time));
} else {
pos = 1.0 - double(animation_time)/double(attacker.get_animation()->get_first_frame_time());
pos = 1.0 - double(animation_time)/double(attacker.get_animation()->get_begin_time());
}
if(attacker.state() != unit::STATE_STANDING && pos > 0.0) {
attacker.set_offset(pos*0.6);

View file

@ -56,6 +56,10 @@ const std::string& progressive_string::get_current_element( int current_time)con
return data_[sub_halo].first;
}
bool progressive_string::does_not_change() const
{
return data_.size() <= 1;
}
progressive_double::progressive_double(const std::string &data, int duration)
@ -124,6 +128,11 @@ int progressive_double::duration() const
}
bool progressive_double::does_not_change() const
{
return data_.empty() ||
( data_.size() == 1 && data_[0].first.first == data_[0].first.second);
}
progressive_int::progressive_int(const std::string &data, int duration)
{
@ -187,38 +196,43 @@ int progressive_int::duration() const
}
bool progressive_int::does_not_change() const
{
return data_.empty() ||
( data_.size() == 1 && data_[0].first.first == data_[0].first.second);
}
unit_frame::unit_frame() :
image_(), image_diagonal_(),halo_(), sound_(),
halo_x_(), halo_y_(), begin_time_(0), end_time_(0),
halo_x_(), halo_y_(), duration_(0),
blend_with_(0),blend_ratio_(),
highlight_ratio_("1.0"),offset_("-20")
{
}
unit_frame::unit_frame(const image::locator& image, int begin,int end,
unit_frame::unit_frame(const image::locator& image, int duration,
const std::string& highlight, const std::string& offset,
Uint32 blend_color, const std::string& blend_rate,
const std::string& in_halo, const std::string& halox, const std::string& haloy,
const image::locator & diag) :
image_(image),image_diagonal_(diag),
halo_(in_halo,end_time_ - begin_time_),
halo_x_(halox,end_time_ - begin_time_),
halo_y_(haloy,end_time_ - begin_time_),
begin_time_(begin), end_time_(end),
blend_with_(blend_color), blend_ratio_(blend_rate,end_time_ - begin_time_),
highlight_ratio_(highlight,end_time_ - begin_time_)
halo_(in_halo,duration),
halo_x_(halox,duration),
halo_y_(haloy,duration),
duration_(duration),
blend_with_(blend_color), blend_ratio_(blend_rate,duration),
highlight_ratio_(highlight,duration)
{
// 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 + 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());
if(offset.empty()) offset_=progressive_double("-20",duration);
else offset_=progressive_double(offset,duration);
duration_ = maximum<int>(duration_, highlight_ratio_.duration());
duration_ = maximum<int>(duration_, blend_ratio_.duration());
duration_ = maximum<int>(duration_, halo_.duration());
duration_ = maximum<int>(duration_, offset_.duration());
}
@ -228,47 +242,59 @@ unit_frame::unit_frame(const config& cfg)
image_ = image::locator(cfg["image"]);
image_diagonal_ = image::locator(cfg["image_diagonal"]);
sound_ = cfg["sound"];
begin_time_ = atoi(cfg["begin"].c_str());
end_time_ = atoi(cfg["end"].c_str());
halo_ = progressive_string(cfg["halo"],end_time_-begin_time_);
halo_x_ = progressive_int(cfg["halo_x"],end_time_ -begin_time_);
halo_y_ = progressive_int(cfg["halo_y"],end_time_ -begin_time_);
if(!cfg["duration"].empty()) {
duration_ = atoi(cfg["duration"].c_str());
} else {
duration_ = atoi(cfg["end"].c_str()) - atoi(cfg["begin"].c_str());
}
halo_ = progressive_string(cfg["halo"],duration_);
halo_x_ = progressive_int(cfg["halo_x"],duration_);
halo_y_ = progressive_int(cfg["halo_y"],duration_);
std::vector<std::string> tmp_blend=utils::split(cfg["blend_color"]);
if(tmp_blend.size() ==3) blend_with_= display::rgb(atoi(tmp_blend[0].c_str()),atoi(tmp_blend[1].c_str()),atoi(tmp_blend[2].c_str()));
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_);
blend_ratio_ = progressive_double(cfg["blend_ratio"],duration_);
highlight_ratio_ = progressive_double(cfg["alpha"].empty()?"1.0":cfg["alpha"],duration_);
offset_ = progressive_double(cfg["offset"].empty()?"-20":cfg["offset"],duration_);
}
const std::string &unit_frame::halo(int current_time) const
{
return halo_.get_current_element(current_time - begin_time_);
return halo_.get_current_element(current_time);
}
double unit_frame::blend_ratio(int current_time) const
{
return blend_ratio_.get_current_element(current_time - begin_time_);
return blend_ratio_.get_current_element(current_time);
}
fixed_t unit_frame::highlight_ratio(int current_time) const
{
return ftofxp(highlight_ratio_.get_current_element(current_time - begin_time_));
return ftofxp(highlight_ratio_.get_current_element(current_time));
}
double unit_frame::offset(int current_time) const
{
return offset_.get_current_element(current_time - begin_time_);
return offset_.get_current_element(current_time);
}
int unit_frame::halo_x(int current_time) const
{
return halo_x_.get_current_element(current_time - begin_time_);
return halo_x_.get_current_element(current_time);
}
int unit_frame::halo_y(int current_time) const
{
return halo_y_.get_current_element(current_time - begin_time_);
return halo_y_.get_current_element(current_time);
}
bool unit_frame::does_not_change() const
{
return halo_.does_not_change() &&
halo_x_.does_not_change() &&
halo_y_.does_not_change() &&
blend_ratio_.does_not_change() &&
highlight_ratio_.does_not_change() &&
offset_.does_not_change();
}

View file

@ -29,6 +29,7 @@ class progressive_string {
progressive_string(const std::string& data = "",int duration = 0);
int duration() const;
const std::string & get_current_element(int time) const;
bool does_not_change() const;
private:
std::vector<std::pair<std::string,int> > data_;
};
@ -38,6 +39,7 @@ class progressive_double {
progressive_double(const std::string& data = "",int duration = 0);
int duration() const;
const double get_current_element(int time) const;
bool does_not_change() const;
private:
std::vector<std::pair<std::pair<double,double>,int> > data_;
};
@ -48,6 +50,7 @@ class progressive_int {
progressive_int(const std::string& data = "",int duration = 0);
int duration() const;
const int get_current_element(int time) const;
bool does_not_change() const;
private:
std::vector<std::pair<std::pair<int,int>,int> > data_;
};
@ -58,7 +61,7 @@ class unit_frame {
public:
// constructors
unit_frame();
explicit unit_frame(const image::locator& image, int begin=0,int end=1,
explicit unit_frame(const image::locator& image, int duration=0,
const std::string& highlight="1.0",const std::string& offset="",
Uint32 blend_color = 0, const std::string& blend_rate = "0",
const std::string & in_halo = "",
@ -72,12 +75,12 @@ class unit_frame {
std::string sound() const { return sound_ ; };
int halo_x(int current_time) const;
int halo_y(int current_time) const;
int begin_time() const { return begin_time_; }
int end_time() const { return end_time_ ; }
int duration() const { return duration_; }
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;
bool does_not_change() const;
private:
image::locator image_;
image::locator image_diagonal_;
@ -86,7 +89,7 @@ class unit_frame {
std::string sound_;
progressive_int halo_x_;
progressive_int halo_y_;
int begin_time_, end_time_;
int duration_;
Uint32 blend_with_;
progressive_double blend_ratio_;
progressive_double highlight_ratio_;

View file

@ -50,7 +50,7 @@ attack_type::attack_type(const config& cfg,const std::string& id, const std::str
animation_.push_back(attack_animation(cfg));
}
if(animation_.empty()) {
animation_.push_back(attack_animation(unit_frame(image_fighting,-200,100)));
animation_.push_back(attack_animation(-200,unit_frame(image_fighting,300)));
}
assert(!animation_.empty());
@ -780,7 +780,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
defensive_animations_.push_back(defensive_animation(**d));
}
if(defensive_animations_.empty()) {
defensive_animations_.push_back(defensive_animation(unit_frame(image(),-150,150)));
defensive_animations_.push_back(defensive_animation(-150,unit_frame(image(),300)));
// always have a defensive animation
}
@ -792,7 +792,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
teleport_animations_.push_back(unit_animation(**t));
}
if(teleport_animations_.empty()) {
teleport_animations_.push_back(unit_animation(unit_frame(image(),-20,20)));
teleport_animations_.push_back(unit_animation(-20,unit_frame(image(),40)));
// always have a defensive animation
}
expanded_cfg = unit_animation::prepare_animation(cfg,"extra_anim");
@ -809,7 +809,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
death_animations_.push_back(death_animation(**death));
}
if(death_animations_.empty()) {
death_animations_.push_back(death_animation(unit_frame(image(),0,10)));
death_animations_.push_back(death_animation(0,unit_frame(image(),10)));
// always have a defensive animation
}
@ -819,7 +819,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
movement_animations_.push_back(movement_animation(**movement_anim));
}
if(movement_animations_.empty()) {
movement_animations_.push_back(movement_animation(unit_frame(image(),0,150)));
movement_animations_.push_back(movement_animation(0,unit_frame(image(),150)));
// always have a movement animation
}
@ -829,7 +829,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
standing_animations_.push_back(standing_animation(**standing_anim));
}
if(standing_animations_.empty()) {
standing_animations_.push_back(standing_animation(unit_frame(image(),0,1)));
standing_animations_.push_back(standing_animation(0,unit_frame(image(),0)));
// always have a standing animation
}
@ -839,7 +839,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
leading_animations_.push_back(leading_animation(**leading_anim));
}
if(leading_animations_.empty()) {
leading_animations_.push_back(leading_animation(unit_frame(image(),0,150)));
leading_animations_.push_back(leading_animation(0,unit_frame(image(),150)));
// always have a leading animation
}
@ -849,7 +849,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(image::locator(cfg["image_healing"]),0,1,"1.0","",0,"",cfg["image_halo_healing"])));
healing_animations_.push_back(healing_animation(0,unit_frame(image::locator(cfg["image_healing"]),1,"1.0","",0,"",cfg["image_halo_healing"])));
// always have a healing animation
}
@ -859,7 +859,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
recruit_animations_.push_back(recruit_animation(**recruit_anim));
}
if(recruit_animations_.empty()) {
recruit_animations_.push_back(recruit_animation(unit_frame(image(),0,600,"0~1:600")));
recruit_animations_.push_back(recruit_animation(0,unit_frame(image(),600,"0~1:600")));
// always have a recruit animation
}
expanded_cfg = unit_animation::prepare_animation(cfg,"idle_anim");
@ -868,7 +868,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
idle_animations_.push_back(idle_animation(**idle_anim));
}
if(idle_animations_.empty()) {
idle_animations_.push_back(idle_animation(unit_frame(image(),0,1)));
idle_animations_.push_back(idle_animation(0,unit_frame(image(),1)));
// always have a idle animation
}
expanded_cfg = unit_animation::prepare_animation(cfg,"levelin_anim");
@ -877,7 +877,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(0,unit_frame(image(),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");
@ -886,7 +886,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(0,unit_frame(image(),600,"1.0","",display::rgb(255,255,255),"0~1:600")));
// always have a levelout animation
}
flag_rgb_ = cfg["flag_rgb"];