wesnoth/src/unit_frame.cpp
2014-06-09 15:26:19 +02:00

988 lines
34 KiB
C++

/*
Copyright (C) 2006 - 2014 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 as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** @file */
#include "global.hpp"
#include "game_display.hpp"
#include "halo.hpp"
#include "sound.hpp"
#include "unit_frame.hpp"
progressive_string::progressive_string(const std::string & data,int duration) :
data_(),
input_(data)
{
const std::vector<std::string> first_pass = utils::square_parenthetical_split(data);
int time_chunk = std::max<int>(duration, 1);
std::vector<std::string>::const_iterator tmp;
if (duration > 1 && first_pass.size() > 0) {
// If duration specified, divide evenly the time for items with unspecified times
int total_specified_time = 0;
for(tmp=first_pass.begin(); tmp != first_pass.end(); ++tmp) {
std::vector<std::string> second_pass = utils::split(*tmp,':');
if(second_pass.size() > 1) {
total_specified_time += atoi(second_pass[1].c_str());
}
}
time_chunk = std::max<int>((duration - total_specified_time) / first_pass.size(), 1);
}
for(tmp=first_pass.begin(); tmp != first_pass.end(); ++tmp) {
std::vector<std::string> second_pass = utils::split(*tmp,':');
if(second_pass.size() > 1) {
data_.push_back(std::pair<std::string,int>(second_pass[0],atoi(second_pass[1].c_str())));
} else {
data_.push_back(std::pair<std::string,int>(second_pass[0],time_chunk));
}
}
}
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) {
total += cur_halo->second;
}
return total;
}
progressive_image::progressive_image(const std::string & data,int duration) :
data_(),
input_(data)
{
const std::vector<std::string> first_pass = utils::square_parenthetical_split(data);
int time_chunk = std::max<int>(duration, 1);
std::vector<std::string>::const_iterator tmp;
if (duration > 1 && first_pass.size() > 0) {
// If duration specified, divide evenly the time for images with unspecified times
int total_specified_time = 0;
for(tmp=first_pass.begin(); tmp != first_pass.end(); ++tmp) {
std::vector<std::string> second_pass = utils::split(*tmp,':');
if(second_pass.size() > 1) {
total_specified_time += atoi(second_pass[1].c_str());
}
}
time_chunk = std::max<int>((duration - total_specified_time) / first_pass.size(), 1);
}
for(tmp=first_pass.begin(); tmp != first_pass.end(); ++tmp) {
std::vector<std::string> second_pass = utils::split(*tmp,':');
if(second_pass.size() > 1) {
data_.push_back(std::pair<image::locator,int>(second_pass[0],atoi(second_pass[1].c_str())));
} else {
data_.push_back(std::pair<image::locator,int>(second_pass[0],time_chunk));
}
}
}
int progressive_image::duration() const
{
int total =0;
std::vector<std::pair<image::locator,int> >::const_iterator cur_halo;
for(cur_halo = data_.begin() ; cur_halo != data_.end() ; ++cur_halo) {
total += cur_halo->second;
}
return total;
}
const image::locator empty_image;
const image::locator& progressive_image::get_current_element(int current_time) const
{
int time = 0;
unsigned int sub_image = 0;
if(data_.empty()) return empty_image;
while(time < current_time&& sub_image < data_.size()) {
time += data_[sub_image].second;
++sub_image;
}
if(sub_image) sub_image--;
return data_[sub_image].first;
}
static const std::string empty_string;
const std::string& progressive_string::get_current_element(int current_time) const
{
int time = 0;
unsigned int sub_halo = 0;
if(data_.empty()) return empty_string;
while(time < current_time&& sub_halo < data_.size()) {
time += data_[sub_halo].second;
++sub_halo;
}
if(sub_halo) sub_halo--;
return data_[sub_halo].first;
}
template <class T>
progressive_<T>::progressive_(const std::string &data, int duration) :
data_(),
input_(data)
{
int split_flag = utils::REMOVE_EMPTY; // useless to strip spaces
const std::vector<std::string> comma_split = utils::split(data,',',split_flag);
const int time_chunk = std::max<int>(1, duration / std::max<int>(comma_split.size(),1));
std::vector<std::string>::const_iterator com_it = comma_split.begin();
for(; com_it != comma_split.end(); ++com_it) {
std::vector<std::string> colon_split = utils::split(*com_it,':',split_flag);
int time = (colon_split.size() > 1) ? atoi(colon_split[1].c_str()) : time_chunk;
std::vector<std::string> range = utils::split(colon_split[0],'~',split_flag);
T range0 = lexical_cast<T>(range[0]);
T range1 = (range.size() > 1) ? lexical_cast<T>(range[1]) : range0;
typedef std::pair<T,T> range_pair;
data_.push_back(std::pair<range_pair,int>(range_pair(range0, range1), time));
}
}
template <class T>
const T progressive_<T>::get_current_element(int current_time, T default_val) const
{
int time = 0;
unsigned int sub_halo = 0;
int searched_time = current_time;
if(searched_time < 0) searched_time = 0;
if(searched_time > duration()) searched_time = duration();
if(data_.empty()) return default_val;
while(time < searched_time&& sub_halo < data_.size()) {
time += data_[sub_halo].second;
++sub_halo;
}
if(sub_halo != 0) {
sub_halo--;
time -= data_[sub_halo].second;
}
const T first = data_[sub_halo].first.first;
const T second = data_[sub_halo].first.second;
return T((static_cast<double>(searched_time - time) /
static_cast<double>(data_[sub_halo].second)) *
(second - first) + first);
}
template<class T>
int progressive_<T>::duration() const
{
int total = 0;
typename std::vector<std::pair<std::pair<T, T>, int> >::const_iterator cur_halo;
for(cur_halo = data_.begin() ; cur_halo != data_.end() ; ++cur_halo) {
total += cur_halo->second;
}
return total;
}
template <class T>
bool progressive_<T>::does_not_change() const
{
return data_.empty() ||
( data_.size() == 1 && data_[0].first.first == data_[0].first.second);
}
// Force compilation of the following template instantiations
template class progressive_<int>;
template class progressive_<double>;
bool tristate_to_bool(tristate tri, bool def)
{
switch(tri)
{
case(t_false):
return false;
case(t_true):
return true;
case(t_unset):
return def;
default:
throw "found unexpected tristate";
}
}
frame_parameters::frame_parameters() :
duration(0),
image(),
image_diagonal(),
image_mod(""),
halo(""),
halo_x(0),
halo_y(0),
halo_mod(""),
sound(""),
text(""),
text_color(0),
blend_with(0),
blend_ratio(0.0),
highlight_ratio(1.0),
offset(0),
submerge(0.0),
x(0),
y(0),
directional_x(0),
directional_y(0),
auto_vflip(t_unset),
auto_hflip(t_unset),
primary_frame(t_unset),
drawing_layer(display::LAYER_UNIT_DEFAULT - display::LAYER_UNIT_FIRST)
{}
frame_builder::frame_builder() :
duration_(1),
image_(),
image_diagonal_(),
image_mod_(""),
halo_(""),
halo_x_(""),
halo_y_(""),
halo_mod_(""),
sound_(""),
text_(""),
text_color_(0),
blend_with_(0),
blend_ratio_(""),
highlight_ratio_(""),
offset_(""),
submerge_(""),
x_(""),
y_(""),
directional_x_(""),
directional_y_(""),
auto_vflip_(t_unset),
auto_hflip_(t_unset),
primary_frame_(t_unset),
drawing_layer_(str_cast(display::LAYER_UNIT_DEFAULT - display::LAYER_UNIT_FIRST))
{}
frame_builder::frame_builder(const config& cfg,const std::string& frame_string) :
duration_(1),
image_(cfg[frame_string + "image"]),
image_diagonal_(cfg[frame_string + "image_diagonal"]),
image_mod_(cfg[frame_string + "image_mod"]),
halo_(cfg[frame_string + "halo"]),
halo_x_(cfg[frame_string + "halo_x"]),
halo_y_(cfg[frame_string + "halo_y"]),
halo_mod_(cfg[frame_string + "halo_mod"]),
sound_(cfg[frame_string + "sound"]),
text_(cfg[frame_string + "text"]),
text_color_(0),
blend_with_(0),
blend_ratio_(cfg[frame_string + "blend_ratio"]),
highlight_ratio_(cfg[frame_string + "alpha"]),
offset_(cfg[frame_string + "offset"]),
submerge_(cfg[frame_string + "submerge"]),
x_(cfg[frame_string + "x"]),
y_(cfg[frame_string + "y"]),
directional_x_(cfg[frame_string + "directional_x"]),
directional_y_(cfg[frame_string + "directional_y"]),
auto_vflip_(t_unset),
auto_hflip_(t_unset),
primary_frame_(t_unset),
drawing_layer_(cfg[frame_string + "layer"])
{
if(!cfg.has_attribute(frame_string + "auto_vflip")) {
auto_vflip_ = t_unset;
} else if(cfg[frame_string + "auto_vflip"].to_bool()) {
auto_vflip_ = t_true;
} else {
auto_vflip_ = t_false;
}
if(!cfg.has_attribute(frame_string + "auto_hflip")) {
auto_hflip_ = t_unset;
} else if(cfg[frame_string + "auto_hflip"].to_bool()) {
auto_hflip_ = t_true;
} else {
auto_hflip_ = t_false;
}
if(!cfg.has_attribute(frame_string + "primary")) {
primary_frame_ = t_unset;
} else if(cfg[frame_string + "primary"].to_bool()) {
primary_frame_ = t_true;
} else {
primary_frame_ = t_false;
}
std::vector<std::string> color = utils::split(cfg[frame_string + "text_color"]);
if (color.size() == 3) {
text_color_ = display::rgb(atoi(color[0].c_str()),
atoi(color[1].c_str()), atoi(color[2].c_str()));
}
if (const config::attribute_value *v = cfg.get(frame_string + "duration")) {
duration(*v);
} else if (!cfg.get(frame_string + "end")) {
int halo_duration = (progressive_string(halo_,1)).duration();
int image_duration = (progressive_image(image_,1)).duration();
int image_diagonal_duration = (progressive_image(image_diagonal_,1)).duration();
duration(std::max(std::max(image_duration,image_diagonal_duration),halo_duration));
} else {
duration(cfg[frame_string + "end"].to_int() - cfg[frame_string + "begin"].to_int());
}
duration_ = std::max(duration_,1);
color = utils::split(cfg[frame_string + "blend_color"]);
if (color.size() == 3) {
blend_with_ = display::rgb(atoi(color[0].c_str()),
atoi(color[1].c_str()), atoi(color[2].c_str()));
}
}
frame_builder & frame_builder::image(const std::string& image ,const std::string & image_mod)
{
image_ = image;
image_mod_ = image_mod;
return *this;
}
frame_builder & frame_builder::image_diagonal(const std::string& image_diagonal,const std::string& image_mod)
{
image_diagonal_ = image_diagonal;
image_mod_ = image_mod;
return *this;
}
frame_builder & frame_builder::sound(const std::string& sound)
{
sound_=sound;
return *this;
}
frame_builder & frame_builder::text(const std::string& text,const Uint32 text_color)
{
text_=text;
text_color_=text_color;
return *this;
}
frame_builder & frame_builder::halo(const std::string &halo, const std::string &halo_x, const std::string& halo_y,const std::string & halo_mod)
{
halo_ = halo;
halo_x_ = halo_x;
halo_y_ = halo_y;
halo_mod_= halo_mod;
return *this;
}
frame_builder & frame_builder::duration(const int duration)
{
duration_= duration;
return *this;
}
frame_builder & frame_builder::blend(const std::string& blend_ratio,const Uint32 blend_color)
{
blend_with_=blend_color;
blend_ratio_=blend_ratio;
return *this;
}
frame_builder & frame_builder::highlight(const std::string& highlight)
{
highlight_ratio_=highlight;
return *this;
}
frame_builder & frame_builder::offset(const std::string& offset)
{
offset_=offset;
return *this;
}
frame_builder & frame_builder::submerge(const std::string& submerge)
{
submerge_=submerge;
return *this;
}
frame_builder & frame_builder::x(const std::string& x)
{
x_=x;
return *this;
}
frame_builder & frame_builder::y(const std::string& y)
{
y_=y;
return *this;
}
frame_builder & frame_builder::directional_x(const std::string& directional_x)
{
directional_x_=directional_x;
return *this;
}
frame_builder & frame_builder::directional_y(const std::string& directional_y)
{
directional_y_=directional_y;
return *this;
}
frame_builder & frame_builder::auto_vflip(const bool auto_vflip)
{
if(auto_vflip) auto_vflip_ = t_true;
else auto_vflip_ = t_false;
return *this;
}
frame_builder & frame_builder::auto_hflip(const bool auto_hflip)
{
if(auto_hflip) auto_hflip_ = t_true;
else auto_hflip_ = t_false;
return *this;
}
frame_builder & frame_builder::primary_frame(const bool primary_frame)
{
if(primary_frame) primary_frame_ = t_true;
else primary_frame_ = t_false;
return *this;
}
frame_builder & frame_builder::drawing_layer(const std::string& drawing_layer)
{
drawing_layer_=drawing_layer;
return *this;
}
frame_parsed_parameters::frame_parsed_parameters(const frame_builder & builder, int duration) :
duration_(duration ? duration :builder.duration_),
image_(builder.image_,duration_),
image_diagonal_(builder.image_diagonal_,duration_),
image_mod_(builder.image_mod_),
halo_(builder.halo_,duration_),
halo_x_(builder.halo_x_,duration_),
halo_y_(builder.halo_y_,duration_),
halo_mod_(builder.halo_mod_),
sound_(builder.sound_),
text_(builder.text_),
text_color_(builder.text_color_),
blend_with_(builder.blend_with_),
blend_ratio_(builder.blend_ratio_,duration_),
highlight_ratio_(builder.highlight_ratio_,duration_),
offset_(builder.offset_,duration_),
submerge_(builder.submerge_,duration_),
x_(builder.x_,duration_),
y_(builder.y_,duration_),
directional_x_(builder.directional_x_,duration_),
directional_y_(builder.directional_y_,duration_),
auto_vflip_(builder.auto_vflip_),
auto_hflip_(builder.auto_hflip_),
primary_frame_(builder.primary_frame_),
drawing_layer_(builder.drawing_layer_,duration_)
{}
bool frame_parsed_parameters::does_not_change() const
{
return image_.does_not_change() &&
image_diagonal_.does_not_change() &&
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() &&
submerge_.does_not_change() &&
x_.does_not_change() &&
y_.does_not_change() &&
directional_x_.does_not_change() &&
directional_y_.does_not_change() &&
drawing_layer_.does_not_change();
}
bool frame_parsed_parameters::need_update() const
{
if(!image_.does_not_change() ||
!image_diagonal_.does_not_change() ||
!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() ||
!submerge_.does_not_change() ||
!x_.does_not_change() ||
!y_.does_not_change() ||
!directional_x_.does_not_change() ||
!directional_y_.does_not_change() ||
!drawing_layer_.does_not_change() ) {
return true;
}
return false;
}
const frame_parameters frame_parsed_parameters::parameters(int current_time) const
{
frame_parameters result;
result.duration = duration_;
result.image = image_.get_current_element(current_time);
result.image_diagonal = image_diagonal_.get_current_element(current_time);
result.image_mod = image_mod_;
result.halo = halo_.get_current_element(current_time);
result.halo_x = halo_x_.get_current_element(current_time);
result.halo_y = halo_y_.get_current_element(current_time);
result.halo_mod = halo_mod_;
result.sound = sound_;
result.text = text_;
result.text_color = text_color_;
result.blend_with = blend_with_;
result.blend_ratio = blend_ratio_.get_current_element(current_time);
result.highlight_ratio = highlight_ratio_.get_current_element(current_time,1.0);
result.offset = offset_.get_current_element(current_time,-1000);
result.submerge = submerge_.get_current_element(current_time);
result.x = x_.get_current_element(current_time);
result.y = y_.get_current_element(current_time);
result.directional_x = directional_x_.get_current_element(current_time);
result.directional_y = directional_y_.get_current_element(current_time);
result.auto_vflip = auto_vflip_;
result.auto_hflip = auto_hflip_;
result.primary_frame = primary_frame_;
result.drawing_layer = drawing_layer_.get_current_element(current_time,display::LAYER_UNIT_DEFAULT-display::LAYER_UNIT_FIRST);
return result;
}
void frame_parsed_parameters::override( int duration
, const std::string& highlight
, const std::string& blend_ratio
, Uint32 blend_color
, const std::string& offset
, const std::string& layer
, const std::string& modifiers)
{
if(!highlight.empty()) {
highlight_ratio_ = progressive_double(highlight,duration);
} else if(duration != duration_){
highlight_ratio_=progressive_double(highlight_ratio_.get_original(),duration);
}
if(!offset.empty()) {
offset_= progressive_double(offset,duration);
} else if(duration != duration_){
offset_=progressive_double(offset_.get_original(),duration);
}
if(!blend_ratio.empty()) {
blend_ratio_ = progressive_double(blend_ratio,duration);
blend_with_ = blend_color;
} else if(duration != duration_){
blend_ratio_=progressive_double(blend_ratio_.get_original(),duration);
}
if(!layer.empty()) {
drawing_layer_ = progressive_int(layer,duration);
} else if(duration != duration_){
drawing_layer_=progressive_int(drawing_layer_.get_original(),duration);
}
if(!modifiers.empty()) {
image_mod_+=modifiers;
}
if(duration != duration_) {
image_ = progressive_image(image_.get_original(),duration);
image_diagonal_ = progressive_image(image_diagonal_.get_original(),duration);
halo_ = progressive_string(halo_.get_original(),duration);
halo_x_ = progressive_int(halo_x_.get_original(),duration);
halo_y_ = progressive_int(halo_y_.get_original(),duration);
submerge_=progressive_double(submerge_.get_original(),duration);
x_=progressive_int(x_.get_original(),duration);
y_=progressive_int(y_.get_original(),duration);
directional_x_=progressive_int(directional_x_.get_original(),duration);
directional_y_=progressive_int(directional_y_.get_original(),duration);
duration_ = duration;
}
}
std::vector<std::string> frame_parsed_parameters::debug_strings() const {
std::vector<std::string> v;
if (duration_>0) v.push_back("duration="+utils::half_signed_value(duration_));
if (!image_.get_original().empty()) v.push_back("image="+image_.get_original());
if (!image_diagonal_.get_original().empty()) v.push_back("image_diagonal="+image_diagonal_.get_original());
if (!image_mod_.empty()) v.push_back("image_mod="+image_mod_);
if (!halo_.get_original().empty()) v.push_back("halo="+halo_.get_original());
if (!halo_x_.get_original().empty()) v.push_back("halo_x="+halo_x_.get_original());
if (!halo_y_.get_original().empty()) v.push_back("halo_y="+halo_y_.get_original());
if (!halo_mod_.empty()) v.push_back("halo_mod="+halo_mod_);
if (!sound_.empty()) v.push_back("sound="+sound_);
if (!text_.empty()) {
v.push_back("text="+text_);
v.push_back("text_color="+str_cast<Uint32>(text_color_));
}
if (!blend_ratio_.get_original().empty()) {
v.push_back("blend_ratio="+blend_ratio_.get_original());
v.push_back("blend_with="+str_cast<Uint32>(blend_with_));
}
if (!highlight_ratio_.get_original().empty()) v.push_back("highlight_ratio="+highlight_ratio_.get_original());
if (!offset_.get_original().empty()) v.push_back("offset="+offset_.get_original());
if (!submerge_.get_original().empty()) v.push_back("submerge="+submerge_.get_original());
if (!x_.get_original().empty()) v.push_back("x="+x_.get_original());
if (!y_.get_original().empty()) v.push_back("y="+y_.get_original());
if (!directional_x_.get_original().empty()) v.push_back("directional_x="+directional_x_.get_original());
if (!directional_y_.get_original().empty()) v.push_back("directional_y="+directional_y_.get_original());
if (auto_vflip_ == t_true) v.push_back("auto_vflip=true");
if (auto_vflip_ == t_false) v.push_back("auto_vflip=false");
if (auto_hflip_ == t_true) v.push_back("auto_hflip=true");
if (auto_hflip_ == t_false) v.push_back("auto_hflip=false");
if (primary_frame_ == t_true) v.push_back("primary_frame=true");
if (primary_frame_ == t_false) v.push_back("primary_frame=false");
if (!drawing_layer_.get_original().empty()) v.push_back("drawing_layer="+drawing_layer_.get_original());
return v;
}
void unit_frame::redraw(const int frame_time,bool on_start_time,bool in_scope_of_frame,const map_location & src,const map_location & dst,int*halo_id,const frame_parameters & animation_val,const frame_parameters & engine_val)const
{
const int xsrc = game_display::get_singleton()->get_location_x(src);
const int ysrc = game_display::get_singleton()->get_location_y(src);
const int xdst = game_display::get_singleton()->get_location_x(dst);
const int ydst = game_display::get_singleton()->get_location_y(dst);
const map_location::DIRECTION direction = src.get_relative_dir(dst);
const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
double tmp_offset = current_data.offset;
// debug code allowing to see the number of frames and their position
// you need to add a '/n'
// if (tmp_offset) std::cout << (int)(tmp_offset*100) << ",";
int d2 = display::get_singleton()->hex_size() / 2;
if(on_start_time ) {
// stuff that should be done only once per frame
if(!current_data.sound.empty() ) {
sound::play_sound(current_data.sound);
}
if(!current_data.text.empty() ) {
game_display::get_singleton()->float_label(src,current_data.text,
(current_data.text_color & 0x00FF0000) >> 16,
(current_data.text_color & 0x0000FF00) >> 8,
(current_data.text_color & 0x000000FF) >> 0);
}
}
image::locator image_loc;
if(direction != map_location::NORTH && direction != map_location::SOUTH) {
image_loc = image::locator(current_data.image_diagonal,current_data.image_mod);
}
if(image_loc.is_void() || image_loc.get_filename() == "") { // invalid diag image, or not diagonal
image_loc = image::locator(current_data.image,current_data.image_mod);
}
surface image;
if(!image_loc.is_void() && image_loc.get_filename() != "") { // invalid diag image, or not diagonal
image=image::get_image(image_loc, image::SCALED_TO_ZOOM);
}
const int x = static_cast<int>(tmp_offset * xdst + (1.0-tmp_offset) * xsrc) + d2;
const int y = static_cast<int>(tmp_offset * ydst + (1.0-tmp_offset) * ysrc) + d2;
if (image != NULL) {
#ifdef LOW_MEM
bool facing_west = false;
#else
bool facing_west = direction == map_location::NORTH_WEST || direction == map_location::SOUTH_WEST;
#endif
bool facing_north = direction == map_location::NORTH_WEST || direction == map_location::NORTH || direction == map_location::NORTH_EAST;
if(!current_data.auto_hflip) facing_west = false;
if(!current_data.auto_vflip) facing_north = true;
int my_x = x + current_data.x- image->w/2;
int my_y = y + current_data.y- image->h/2;
if(facing_west) {
my_x -= current_data.directional_x;
} else {
my_x += current_data.directional_x;
}
if(facing_north) {
my_y += current_data.directional_y;
} else {
my_y -= current_data.directional_y;
}
game_display::get_singleton()->render_image( my_x,my_y,
static_cast<display::tdrawing_layer>(display::LAYER_UNIT_FIRST+current_data.drawing_layer),
src, image, facing_west, false,
ftofxp(current_data.highlight_ratio), current_data.blend_with,
current_data.blend_ratio,current_data.submerge,!facing_north);
}
halo::remove(*halo_id);
*halo_id = halo::NO_HALO;
if (!in_scope_of_frame) { //check after frame as first/last frame image used in defense/attack anims
return;
}
if(!current_data.halo.empty()) {
halo::ORIENTATION orientation;
switch(direction)
{
case map_location::NORTH:
case map_location::NORTH_EAST:
orientation = halo::NORMAL;
break;
case map_location::SOUTH_EAST:
case map_location::SOUTH:
if(!current_data.auto_vflip) {
orientation = halo::NORMAL;
} else {
orientation = halo::VREVERSE;
}
break;
case map_location::SOUTH_WEST:
if(!current_data.auto_vflip) {
orientation = halo::HREVERSE;
} else {
orientation = halo::HVREVERSE;
}
break;
case map_location::NORTH_WEST:
orientation = halo::HREVERSE;
break;
case map_location::NDIRECTIONS:
default:
orientation = halo::NORMAL;
break;
}
if(direction != map_location::SOUTH_WEST && direction != map_location::NORTH_WEST) {
*halo_id = halo::add(static_cast<int>(x+current_data.halo_x* game_display::get_singleton()->get_zoom_factor()),
static_cast<int>(y+current_data.halo_y* game_display::get_singleton()->get_zoom_factor()),
current_data.halo + current_data.halo_mod,
map_location(-1, -1),
orientation);
} else {
*halo_id = halo::add(static_cast<int>(x-current_data.halo_x* game_display::get_singleton()->get_zoom_factor()),
static_cast<int>(y+current_data.halo_y* game_display::get_singleton()->get_zoom_factor()),
current_data.halo + current_data.halo_mod,
map_location(-1, -1),
orientation);
}
}
}
std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time,const map_location & src,const map_location & dst,const frame_parameters & animation_val,const frame_parameters & engine_val) const
{
display* disp = display::get_singleton();
const int xsrc = disp->get_location_x(src);
const int ysrc = disp->get_location_y(src);
const int xdst = disp->get_location_x(dst);
const int ydst = disp->get_location_y(dst);
const map_location::DIRECTION direction = src.get_relative_dir(dst);
const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
double tmp_offset = current_data.offset;
int d2 = game_display::get_singleton()->hex_size() / 2;
image::locator image_loc;
if(direction != map_location::NORTH && direction != map_location::SOUTH) {
image_loc = image::locator(current_data.image_diagonal,current_data.image_mod);
}
if(image_loc.is_void() || image_loc.get_filename() == "") { // invalid diag image, or not diagonal
image_loc = image::locator(current_data.image,current_data.image_mod);
}
// we always invalidate our own hex because we need to be called at redraw time even
// if we don't draw anything in the hex itself
std::set<map_location> result;
if(tmp_offset==0 && current_data.x == 0 && current_data.directional_x == 0 && image::is_in_hex(image_loc)) {
result.insert(src);
int my_y = current_data.y;
bool facing_north = direction == map_location::NORTH_WEST || direction == map_location::NORTH || direction == map_location::NORTH_EAST;
if(!current_data.auto_vflip) facing_north = true;
if(facing_north) {
my_y += current_data.directional_y;
} else {
my_y -= current_data.directional_y;
}
if(my_y < 0) {
result.insert(src.get_direction(map_location::NORTH));
result.insert(src.get_direction(map_location::NORTH_EAST));
result.insert(src.get_direction(map_location::NORTH_WEST));
} else if(my_y > 0) {
result.insert(src.get_direction(map_location::SOUTH));
result.insert(src.get_direction(map_location::SOUTH_EAST));
result.insert(src.get_direction(map_location::SOUTH_WEST));
}
} else {
int w=0;
int h =0;
#ifdef _OPENMP
#pragma omp critical(frame_surface) // with the way surfaces work it's hard to lock the refcount within sdl_utils
#endif //_OPENMP
{
surface image;
if(!image_loc.is_void() && image_loc.get_filename() != "") { // invalid diag image, or not diagonal
image=image::get_image(image_loc,
image::SCALED_TO_ZOOM
);
}
if(image != NULL) {
w = image->w;
h = image->h;
}
}
if (w != 0 || h != 0) {
const int x = static_cast<int>(tmp_offset * xdst + (1.0-tmp_offset) * xsrc);
const int y = static_cast<int>(tmp_offset * ydst + (1.0-tmp_offset) * ysrc);
#ifdef LOW_MEM
bool facing_west = false;
#else
bool facing_west = direction == map_location::NORTH_WEST || direction == map_location::SOUTH_WEST;
#endif
bool facing_north = direction == map_location::NORTH_WEST || direction == map_location::NORTH || direction == map_location::NORTH_EAST;
if(!current_data.auto_vflip) facing_north = true;
if(!current_data.auto_hflip) facing_west = false;
int my_x = x +current_data.x+d2- w/2;
int my_y = y +current_data.y+d2- h/2;
if(facing_west) {
my_x += current_data.directional_x;
} else {
my_x -= current_data.directional_x;
}
if(facing_north) {
my_y += current_data.directional_y;
} else {
my_y -= current_data.directional_y;
}
const SDL_Rect r = sdl::create_rect(my_x, my_y, w, h);
// check if our underlying hexes are invalidated
// if we need to update ourselves because we changed, invalidate our hexes
// and return whether or not our hexes was invalidated
// invalidate ourself to be called at redraw time
result.insert(src);
display::rect_of_hexes underlying_hex = disp->hexes_under_rect(r);
result.insert(underlying_hex.begin(),underlying_hex.end());
} else {
// we have no "redraw surface" but we still need to invalidate our own hex
// in case we have a halo and/or sound that needs a redraw
// invalidate ourself to be called at redraw time
result.insert(src);
result.insert(dst);
}
}
return result;
}
const frame_parameters unit_frame::merge_parameters(int current_time,const frame_parameters & animation_val,const frame_parameters & engine_val) const
{
/**
* this function merges the value provided by
* * the frame
* * the engine (poison, flying unit...)
* * the animation as a whole
* there is no absolute rule for merging, so creativity is the rule
* if a value is never provided by the engine, assert. (this way if it becomes used, people will easily find the right place to look)
*
*/
frame_parameters result;
const frame_parameters & current_val = builder_.parameters(current_time);
result.primary_frame = engine_val.primary_frame;
if(animation_val.primary_frame != t_unset) result.primary_frame = animation_val.primary_frame;
if(current_val.primary_frame != t_unset) result.primary_frame = current_val.primary_frame;
const bool primary = tristate_to_bool(result.primary_frame, true);
/** engine provides a default image to use for the unit when none is available */
result.image = current_val.image.is_void() || current_val.image.get_filename() == ""?animation_val.image:current_val.image;
if(primary && ( result.image.is_void() || result.image.get_filename().empty())) {
result.image = engine_val.image;
}
/** engine provides a default image to use for the unit when none is available */
result.image_diagonal = current_val.image_diagonal.is_void() || current_val.image_diagonal.get_filename() == ""?animation_val.image_diagonal:current_val.image_diagonal;
if(primary && ( result.image_diagonal.is_void() || result.image_diagonal.get_filename().empty())) {
result.image_diagonal = engine_val.image_diagonal;
}
/** engine provides a string for "petrified" and "team color" modifications
note that image_mod is the complete modification and halo_mod is only the TC part
see unit.cpp, we know that and use it*/
result.image_mod = current_val.image_mod +animation_val.image_mod;
if(primary) {
result.image_mod += engine_val.image_mod;
} else {
result.image_mod += engine_val.halo_mod;
}
assert(engine_val.halo.empty());
result.halo = current_val.halo.empty()?animation_val.halo:current_val.halo;
assert(engine_val.halo_x == 0);
result.halo_x = current_val.halo_x?current_val.halo_x:animation_val.halo_x;
/** the engine provide y modification for terrain with height adjust and flying units */
result.halo_y = current_val.halo_y?current_val.halo_y:animation_val.halo_y;
result.halo_y += engine_val.halo_y;
result.halo_mod = current_val.halo_mod +animation_val.halo_mod;
result.halo_mod += engine_val.halo_mod;
assert(engine_val.duration == 0);
result.duration = current_val.duration;
assert(engine_val.sound.empty());
result.sound = current_val.sound.empty()?animation_val.sound:current_val.sound;
assert(engine_val.text.empty());
result.text = current_val.text.empty()?animation_val.text:current_val.text;
assert(engine_val.text_color == 0);
result.text_color = current_val.text_color?current_val.text_color:animation_val.text_color;
/** engine provide a blend color for poisoned units */
result.blend_with = current_val.blend_with?current_val.blend_with:animation_val.blend_with;
if(primary&& engine_val.blend_with) result.blend_with = display::max_rgb(engine_val.blend_with,result.blend_with);
/** engine provide a blend color for poisoned units */
result.blend_ratio = current_val.blend_ratio?current_val.blend_ratio:animation_val.blend_ratio;
if(primary && engine_val.blend_ratio) {
result.blend_ratio = std::min(
result.blend_ratio + engine_val.blend_ratio
, 1.0);
}
/** engine provide a highlight ratio for selected units and visible "invisible" units */
result.highlight_ratio = current_val.highlight_ratio!=1.0?current_val.highlight_ratio:animation_val.highlight_ratio;
if(primary && engine_val.highlight_ratio != 1.0) result.highlight_ratio = result.highlight_ratio +engine_val.highlight_ratio - 1.0; // selected unit
assert(engine_val.offset == 0);
result.offset = (current_val.offset!=-1000)?current_val.offset:animation_val.offset;
if(result.offset == -1000) result.offset = 0.0;
/** engine provides a submerge for units in water */
result.submerge = current_val.submerge?current_val.submerge:animation_val.submerge;
if(primary && engine_val.submerge && !result.submerge ) result.submerge = engine_val.submerge;
assert(engine_val.x == 0);
result.x = current_val.x?current_val.x:animation_val.x;
/** the engine provide y modification for terrain with height adjust and flying units */
result.y = current_val.y?current_val.y:animation_val.y;
result.y += engine_val.y;
assert(engine_val.directional_x == 0);
result.directional_x = current_val.directional_x?current_val.directional_x:animation_val.directional_x;
assert(engine_val.directional_y == 0);
result.directional_y = current_val.directional_y?current_val.directional_y:animation_val.directional_y;
assert(engine_val.drawing_layer == display::LAYER_UNIT_DEFAULT-display::LAYER_UNIT_FIRST);
result.drawing_layer = current_val.drawing_layer != display::LAYER_UNIT_DEFAULT-display::LAYER_UNIT_FIRST?
current_val.drawing_layer:animation_val.drawing_layer;
/** the engine provide us with default value to compare with, we update if different */
result.auto_hflip = engine_val.auto_hflip;
if(animation_val.auto_hflip != t_unset) result.auto_hflip = animation_val.auto_hflip;
if(current_val.auto_hflip != t_unset) result.auto_hflip = current_val.auto_hflip;
if(result.auto_hflip == t_unset) result.auto_hflip = t_true;
result.auto_vflip = engine_val.auto_vflip;
if(animation_val.auto_vflip != t_unset) result.auto_vflip = animation_val.auto_vflip;
if(current_val.auto_vflip != t_unset) result.auto_vflip = current_val.auto_vflip;
if(result.auto_vflip == t_unset) {
if(primary) result.auto_vflip=t_false;
else result.auto_vflip = t_true;
}
#ifdef LOW_MEM
if(primary) {
result.image= engine_val.image;
result.image_diagonal= engine_val.image;
}
#endif
return result;
}