the long promissed new animation engine... report all glitches to me (boucman)

This commit is contained in:
Jérémy Rosen 2006-03-24 19:17:23 +00:00
parent 3a7c85d63b
commit 4c14bd8a32
25 changed files with 880 additions and 1210 deletions

View file

@ -38,6 +38,8 @@ SVN trunk (1.1.2+svn):
* updated translations: Czech, German, Korean, Norwegian
* units
* fixed the resistances of the Sky Drake line
* Wesnoth engine
* new unit display graphic engine...
Version 1.1.2:
* campaigns

View file

@ -142,25 +142,11 @@
[/missile_frame]
[frame]
begin=-200
end=-100
image="units/drakes/blademaster-attack-ranged.png"
halo=halo/fireball-preparation-1.png,halo/fireball-preparation-2.png,halo/fireball-preparation-3.png,halo/fireball-preparation-4.png
halo_x,halo_y=10,-2
[/frame]
[frame]
sound=flame-big.ogg
begin=-100
end=-99
halo=halo/fireball-preparation-1.png,halo/fireball-preparation-2.png,halo/fireball-preparation-3.png,halo/fireball-preparation-4.png
halo_x,halo_y=10,-2
image="units/drakes/blademaster-attack-ranged.png"
[/frame]
[frame]
begin=-99
end=-50
image="units/drakes/blademaster-attack-ranged.png"
halo=halo/fireball-preparation-1.png,halo/fireball-preparation-2.png,halo/fireball-preparation-3.png,halo/fireball-preparation-4.png
halo_x,halo_y=10,-2
sound=flame-big.ogg
[/frame]
[/animation]
[/attack]

View file

@ -114,25 +114,11 @@
[/missile_frame]
[frame]
begin=-250
end=-175
image="units/drakes/fire-attack-ranged.png"
halo=halo/fireball-preparation-1.png,halo/fireball-preparation-2.png,halo/fireball-preparation-3.png,halo/fireball-preparation-4.png
halo_x,halo_y=12,-2
[/frame]
[frame]
sound=flame-big.ogg
begin=-175
end=-174
halo=halo/fireball-preparation-1.png,halo/fireball-preparation-2.png,halo/fireball-preparation-3.png,halo/fireball-preparation-4.png
halo_x,halo_y=12,-2
image="units/drakes/fire-attack-ranged.png"
[/frame]
[frame]
begin=-174
end=-50
image="units/drakes/fire-attack-ranged.png"
halo=halo/fireball-preparation-1.png,halo/fireball-preparation-2.png,halo/fireball-preparation-3.png,halo/fireball-preparation-4.png
halo_x,halo_y=12,-2
sound=flame-big.ogg
[/frame]
[/animation]
[/attack]

View file

@ -139,22 +139,8 @@ Special Notes: the ranged attack of a silver mage is magical, and always has a h
[/frame]
[frame]
begin=-350
end=-200
image="units/human-magi/silver-mage-attack-magic1.png"
halo=halo/mage-preparation-halo1.png,halo/mage-preparation-halo2.png,halo/mage-preparation-halo3.png,halo/mage-preparation-halo4.png,halo/mage-preparation-halo5.png,halo/mage-preparation-halo6.png,halo/mage-preparation-halo7.png
halo_x,halo_y=19,-15
[/frame]
[frame]
sound=magicmissile.wav
begin=-200
end=-199
halo=halo/mage-preparation-halo1.png,halo/mage-preparation-halo2.png,halo/mage-preparation-halo3.png,halo/mage-preparation-halo4.png,halo/mage-preparation-halo5.png,halo/mage-preparation-halo6.png,halo/mage-preparation-halo7.png
halo_x,halo_y=19,-15
image="units/human-magi/silver-mage-attack-magic1.png"
[/frame]
[frame]
begin=-199
end=0
sound=magicmissile.wav
image="units/human-magi/silver-mage-attack-magic1.png"
halo=halo/mage-preparation-halo1.png,halo/mage-preparation-halo2.png,halo/mage-preparation-halo3.png,halo/mage-preparation-halo4.png,halo/mage-preparation-halo5.png,halo/mage-preparation-halo6.png,halo/mage-preparation-halo7.png
halo_x,halo_y=19,-15

View file

@ -147,21 +147,25 @@ std::string recruit_unit(const gamemap& map, int side,
disp->draw(true,true);
}
units.insert(std::pair<gamemap::location,unit>(
recruit_location,new_unit));
units.insert(std::pair<gamemap::location,unit>( recruit_location,new_unit));
unit_map::iterator un = units.find(recruit_location);
LOG_NG << "firing recruit event\n";
game_events::fire("recruit",recruit_location);
if(show) {
for(fixed_t alpha = ftofxp(0.0); alpha <= ftofxp(1.0); alpha += ftofxp(0.1)) {
events::pump();
disp->draw_tile(recruit_location.x,recruit_location.y,NULL,alpha);
un->second.set_recruited(disp->turbo()?5:1);
disp->scroll_to_tile(recruit_location.x,recruit_location.y,display::ONSCREEN);
while(!un->second.get_animation()->animation_finished()) {
disp->draw_tile(recruit_location.x,recruit_location.y);
disp->update_display();
SDL_Delay(20);
events::pump();
if(!disp->turbo()) SDL_Delay(10);
}
}
un->second.set_standing(disp->turbo()?5:1);
LOG_NG << "firing recruit event\n";
game_events::fire("recruit",recruit_location);
checksumstream cs;
config cfg_unit;
@ -1575,6 +1579,8 @@ void calculate_healing(display& disp, const gamestatus& status, const gamemap& m
typedef std::multimap<gamemap::location,gamemap::location>::const_iterator healer_itor;
const std::pair<healer_itor,healer_itor> healer_itors = healers.equal_range(loc);
// time at which we start all anmations
int start_time = 0;
if(show_healing) {
disp.scroll_to_tile(loc.x,loc.y,display::ONSCREEN);
disp.select_hex(loc);
@ -1585,32 +1591,11 @@ void calculate_healing(display& disp, const gamestatus& status, const gamemap& m
for(healer_itor i = healer_itors.first; i != healer_itors.second; ++i) {
wassert(units.count(i->second));
unit& healer = units.find(i->second)->second;
const std::string& halo_image = healer.type().image_halo_healing();
//only show healing frames if haloing is enabled, or if there is no halo
if(halo_image.empty() || preferences::show_haloes()) {
healer.set_healing();
if(halo_image.empty() == false) {
int height_adjust = healer.is_flying() ? 0 :
int(map.get_terrain_info(map.get_terrain(i->second)).
unit_height_adjust() * disp.zoom());
int d = disp.hex_size();
halo::add(disp.get_location_x(i->second) + d / 2,
disp.get_location_y(i->second) + d / 2 - height_adjust,
halo_image, healer.facing_left() ? halo::NORMAL :
halo::REVERSE, 1);
}
disp.draw_tile(i->second.x,i->second.y);
}
healer.set_healing(disp.turbo()?5:1);
start_time = minimum<int>(start_time,healer.get_animation()->get_first_frame_time());
}
disp.update_display();
}
const int DelayAmount = 50;
LOG_NG << "unit is poisoned? " << (u.has_flag("poisoned") ? "yes" : "no") << ","
<< h->second << "," << max_healing[h->first] << "\n";
@ -1626,9 +1611,6 @@ void calculate_healing(display& disp, const gamestatus& status, const gamemap& m
if(show_healing) {
sound::play_sound("heal.wav");
SDL_Delay(DelayAmount);
disp.invalidate_unit();
disp.update_display();
}
}
@ -1653,57 +1635,50 @@ void calculate_healing(display& disp, const gamestatus& status, const gamemap& m
}
}
while(h->second > 0) {
const Uint32 heal_colour = disp.rgb(0,0,200);
u.heal(1);
if(show_healing) {
if(is_odd(h->second))
disp.draw_tile(loc.x,loc.y,NULL,ftofxp(0.5),heal_colour);
else
disp.draw_tile(loc.x,loc.y);
events::pump();
SDL_Delay(DelayAmount);
disp.update_display();
}
--h->second;
if(h->second > 0) {
u.set_healed(h->second,disp.turbo()?5:1);
start_time = minimum<int>(start_time,u.get_animation()->get_first_frame_time());
}
while(h->second < 0) {
const Uint32 damage_colour = disp.rgb(200,0,0);
u.gets_hit(1);
if(show_healing) {
if(is_odd(h->second))
disp.draw_tile(loc.x,loc.y,NULL,ftofxp(0.5),damage_colour);
else
disp.draw_tile(loc.x,loc.y);
events::pump();
SDL_Delay(DelayAmount);
disp.update_display();
}
++h->second;
if(h->second < 0) {
u.set_poisoned(-h->second,disp.turbo()?5:1);
start_time = minimum<int>(start_time,u.get_animation()->get_first_frame_time());
}
if(show_healing) {
std::vector<unit*>::iterator itor;
// restart all anims in a synchronized way
u.restart_animation(start_time,disp.turbo()?5:1);
for(healer_itor i = healer_itors.first; i != healer_itors.second; ++i) {
unit& healer = units.find(i->second)->second;
healer.restart_animation(start_time,disp.turbo()?5:1);
}
bool finished = false;
while(!finished) {
finished = (u.get_animation()->animation_finished());
disp.draw_tile(loc.x,loc.y);
for(healer_itor i = healer_itors.first; i != healer_itors.second; ++i) {
wassert(units.count(i->second));
unit& healer = units.find(i->second)->second;
healer.set_standing();
events::pump();
finished = (finished && u.get_animation()->animation_finished());
disp.draw_tile(i->second.x,i->second.y);
}
disp.draw_tile(loc.x,loc.y);
if(h->second > 0) {
u.heal(1);
--h->second;
} else if (h->second <0) {
u.gets_hit(1);
++h->second;
}
finished &= (h->second ==0);
disp.update_display();
events::pump();
if(!disp.turbo()) SDL_Delay(10);
}
u.set_standing(disp.turbo()?5:1);
for(healer_itor i = healer_itors.first; i != healer_itors.second; ++i) {
unit& healer = units.find(i->second)->second;
healer.set_standing(disp.turbo()?5:1);
}
disp.update_display();
events::pump();
}
}
@ -2112,15 +2087,14 @@ size_t move_unit(display* disp, const game_data& gamedata,
//remove it until the move is done, so that while the unit is moving status etc will
//still display the correct number of units.
if(disp != NULL) {
disp->hide_unit(ui->first,true);
ui->second.set_hidden(true);
disp->draw_tile(ui->first.x,ui->first.y);
unit_display::move_unit(*disp,map,steps,u,status.get_time_of_day(),units,teams);
ui->second.set_hidden(false);
}
u.set_movement(moves_left);
if(disp != NULL) {
disp->hide_unit(gamemap::location());
}
units.erase(ui);
ui = units.insert(std::pair<gamemap::location,unit>(steps.back(),u)).first;

View file

@ -476,9 +476,9 @@ gamemap::location ai_interface::move_unit_partial(location from, location to, st
info_.disp.scroll_to_tiles(from.x,from.y,to.x,to.y);
info_.disp.hide_unit(u_it->first,true);
u_it->second.set_hidden(true);
unit_display::move_unit(info_.disp,info_.map,steps,current_unit,info_.state.get_time_of_day(),info_.units,info_.teams);
info_.disp.hide_unit(gamemap::location());
u_it->second.set_hidden(false);
info_.units.erase(u_it);
u_it = info_.units.end();
}

View file

@ -107,7 +107,6 @@ void animated<T,T_void_value>::start_animation(int start_frame, int cycles, int
} else {
duration_ = 0;
}
no_current_frame_ = false;
frame_changed_ = true;
}
@ -183,10 +182,12 @@ void animated<T,T_void_value>::update_current_frame()
} else {
// If the duration is void, the animation is automatically finished.
// current_cycle_ = cycles_;
if(cycles_ != -1)
if(cycles_ != -1) {
started_ = false;
} else {
does_not_change_ = true;
}
frame_changed_ = false;
// current_frame_ = frames_.size() - 1;
// frame_changed_ = false;
@ -280,13 +281,6 @@ int animated<T,T_void_value>::get_last_frame_time() const
}
template<typename T, typename T_void_value>
void animated<T, T_void_value>::synchronize_start(animated<T> &a, animated<T> &b,int acceleration)
{
int start_time = minimum<int>(a.get_first_frame_time(),b.get_first_frame_time());
a.start_animation(start_time,1,acceleration);
b.start_animation(start_time,1,acceleration);
}
// Force compilation of the following template instantiations
#include "image.hpp"

View file

@ -72,7 +72,6 @@ public:
const T& get_last_frame() const;
static void synchronize_start(animated<T> &a, animated<T>& b,int acceleration);
private:
struct frame

View file

@ -133,12 +133,12 @@ bool animate_unit_advancement(const game_data& info,unit_map& units, gamemap::lo
//new unit, then fades back to the normal colour
if(!gui.update_locked()) {
for(double intensity = 1.0; intensity >= 0.0; intensity -= 0.05) {
gui.set_advancing_unit(loc,intensity);
events::pump();
gui.draw(false);
u->second.set_leveling_out(gui.turbo()?5:1);
while(!u->second.get_animation()->animation_finished()) {
gui.draw_tile(loc.x,loc.y);
gui.update_display();
SDL_Delay(30);
events::pump();
if(!gui.turbo()) SDL_Delay(10);
}
}
@ -156,17 +156,19 @@ bool animate_unit_advancement(const game_data& info,unit_map& units, gamemap::lo
gui.invalidate_unit();
if(!gui.update_locked()) {
for(double intensity = 0.0; intensity <= 1.0; intensity += 0.05) {
gui.set_advancing_unit(loc,intensity);
events::pump();
gui.draw(false);
u->second.set_leveling_in(gui.turbo()?5:1);
while(!u->second.get_animation()->animation_finished()) {
gui.draw_tile(loc.x,loc.y);
gui.update_display();
SDL_Delay(30);
events::pump();
if(!gui.turbo()) SDL_Delay(10);
}
u->second.set_standing(gui.turbo()?5:1);
gui.draw_tile(loc.x,loc.y);
gui.update_display();
events::pump();
}
gui.set_advancing_unit(gamemap::location(),0.0);
gui.invalidate_all();
gui.draw();
@ -681,10 +683,7 @@ void unit_preview_pane::draw_contents()
SDL_Rect clip_area = area;
const clip_rect_setter clipper(screen,clip_area);
surface unit_image(image::get_image(u.image_loc(),image::UNSCALED));
if(left_side() == false && unit_image != NULL) {
unit_image.assign(image::reverse_image(unit_image));
}
surface unit_image = u.still_image();
SDL_Rect image_rect = {area.x,area.y,0,0};

View file

@ -85,8 +85,7 @@ display::display(unit_map& units, CVideo& video, const gamemap& map,
teams_(t), lastDraw_(0), drawSkips_(0),
invalidateAll_(true), invalidateUnit_(true),
invalidateGameStatus_(true), panelsDrawn_(false),
currentTeam_(0), activeTeam_(0), hideEnergy_(false),
deadAmount_(ftofxp(0.0)), advancingAmount_(0.0),
currentTeam_(0), activeTeam_(0),
turbo_(false), grid_(false), sidebarScaling_(1.0),
theme_(theme_cfg,screen_area()), builder_(cfg, level, map),
first_turn_(true), in_game_(false), map_labels_(*this,map),
@ -218,13 +217,6 @@ void display::adjust_colours(int r, int g, int b)
image::set_colour_adjustment(tod.red+r,tod.green+g,tod.blue+b);
}
gamemap::location display::hide_unit(const gamemap::location& loc, bool hide_energy)
{
const gamemap::location res = hiddenUnit_;
hiddenUnit_ = loc;
hideEnergy_ = hide_energy;
return res;
}
int display::x() const { return screen_.getx(); }
int display::mapx() const { return x() - 140; }
@ -1228,232 +1220,30 @@ void display::draw_minimap(int x, int y, int w, int h)
update_rect(minimap_location);
}
void display::draw_halo_on_tile(int x, int y)
void display::draw_unit_on_tile(int x, int y,double offset)
{
const gamemap::location loc(x,y);
int xpos = get_location_x(loc);
int ypos = get_location_y(loc);
const halo_map::iterator halo_it = haloes_.find(loc);
const gamemap::location src(x,y);
//see if there is a unit on this tile
const unit_map::const_iterator it = fogged(x,y) ? units_.end() : units_.find(gamemap::location(x,y));
if(halo_it != haloes_.end() && it == units_.end()) {
halo::remove(halo_it->second);
haloes_.erase(halo_it);
} else if(halo_it == haloes_.end() && it != units_.end()) {
const std::string& halo = it->second.type().image_halo();
if(halo.empty() == false) {
haloes_.insert(std::pair<gamemap::location,int>(loc,halo::add(xpos+hex_width()/2,ypos+hex_size()/2,halo)));
}
}
}
void display::draw_unit_on_tile(int x, int y, surface unit_image_override,
fixed_t highlight_ratio, Uint32 blend_with)
{
if(screen_.update_locked()) {
return;
}
const gamemap::location loc(x,y);
int xpos = get_location_x(loc);
int ypos = get_location_y(loc);
//see if there is a unit on this tile
const unit_map::const_iterator it = units_.find(loc);
unit_map::iterator it = units_.find(src);
if(it == units_.end()) {
return;
}
SDL_Rect clip_rect = map_area();
if(xpos > clip_rect.x + clip_rect.w || ypos > clip_rect.y + clip_rect.h ||
xpos + zoom_ < clip_rect.x || ypos + zoom_ < clip_rect.y) {
return;
}
const gamemap::location dst= src.get_direction(it->second.facing());
const double xsrc = get_location_x(src);
const double ysrc = get_location_y(src);
const double xdst = get_location_x(dst);
const double ydst = get_location_y(dst);
surface const dst(screen_.getSurface());
const int posx = int(offset*xdst + (1.0-offset)*xsrc);
const int posy = int(offset*ydst + (1.0-offset)*ysrc);
clip_rect_setter set_clip_rect(dst,clip_rect);
double unit_energy = 0.0;
it->second.refresh_unit(*this,src,posx,posy,true);
surface unit_image(unit_image_override);
const std::string* movement_file = NULL;
const std::string* energy_file = &game_config::energy_image;
const unit& u = it->second;
SDL_Color energy_colour = u.hp_color();
if(loc != hiddenUnit_ || !hideEnergy_) {
if(unit_image == NULL) {
unit_image.assign(image::get_image(u.image_loc(),it->second.stone() ? image::GREYED : image::SCALED));
}
if(unit_image == NULL) {
return;
}
const int unit_move = it->second.movement_left();
const int unit_total_move = it->second.total_movement();
if(size_t(u.side()) != currentTeam_+1) {
if(team_valid() &&
teams_[currentTeam_].is_enemy(it->second.side())) {
movement_file = &game_config::enemy_ball_image;
} else {
movement_file = &game_config::ally_ball_image;
}
} else {
if(activeTeam_ == currentTeam_ && unit_move == unit_total_move && !it->second.user_end_turn()) {
movement_file = &game_config::unmoved_ball_image;
} else if(activeTeam_ == currentTeam_ && unit_can_move(loc,units_,map_,teams_) && !it->second.user_end_turn()) {
movement_file = &game_config::partmoved_ball_image;
} else {
movement_file = &game_config::moved_ball_image;
}
}
wassert(movement_file != NULL);
if(movement_file == NULL) {
ERR_DP << "movement file is NULL\n";
return;
}
wassert(energy_file != NULL);
if(energy_file == NULL) {
ERR_DP << "energy file is NULL\n";
return;
}
if(highlight_ratio == ftofxp(1.0)) {
highlight_ratio = it->second.alpha();
}
if(u.invisible(map_.underlying_union_terrain(map_[x][y]),
status_.get_time_of_day().lawful_bonus,loc,
units_,teams_) &&
highlight_ratio > ftofxp(0.5)) {
highlight_ratio = ftofxp(0.5);
}
if(loc == selectedHex_ && highlight_ratio == ftofxp(1.0)) {
highlight_ratio = ftofxp(1.5);
// blend_with = rgb(255,255,255);
}
if(u.max_hitpoints() > 0) {
unit_energy = double(u.hitpoints())/double(u.max_hitpoints());
}
if(u.facing_left() == false) {
//reverse the image here. image::reverse_image is more efficient, however
//it can be used only if we are sure that unit_image came from image::get_image.
//Since we aren't sure of that in the case of overrides, use the less efficient
//flip_surface if the image has been over-ridden.
if(unit_image_override == NULL) {
unit_image.assign(image::reverse_image(unit_image));
} else {
unit_image.assign(flip_surface(unit_image));
}
}
}
if(deadUnit_ == gamemap::location(x,y)) {
highlight_ratio = deadAmount_;
}
if(unit_image == NULL || fogged(x,y) ||
(teams_[currentTeam_].is_enemy(it->second.side()) &&
it->second.invisible(map_.underlying_union_terrain(map_[x][y]),
status_.get_time_of_day().lawful_bonus,loc,
units_,teams_))) {
return;
}
const gamemap::TERRAIN terrain = map_.get_terrain(loc);
const int height_adjust = it->second.is_flying() ? 0 : int(map_.get_terrain_info(terrain).unit_height_adjust()*zoom());
const double submerge = it->second.is_flying() ? 0.0 : map_.get_terrain_info(terrain).unit_submerge();
double blend_ratio = 0.0;
if(loc == advancingUnit_ && it != units_.end()) {
//the unit is advancing - set the advancing colour to white if it's a
//non-chaotic unit, otherwise black
blend_with = it->second.type().alignment() == unit_type::CHAOTIC ?
rgb(16,16,16) : rgb(255,255,255);
blend_ratio = 1 - advancingAmount_;
} else if(it->second.poisoned() /* && highlight_ratio == 1.0 */) {
//the unit is poisoned - draw with a green hue
blend_with = rgb(0,255,0);
blend_ratio = 0.25;
//highlight_ratio *= 0.75;
}
if(loc != hiddenUnit_) {
surface ellipse_front(NULL);
surface ellipse_back(NULL);
if(preferences::show_side_colours()) {
const char* const selected = selectedHex_ == loc ? "selected-" : "";
std::vector<Uint32> temp_rgb;
//ellipse not pure red=255!
for(int i=255;i>100;i--){
temp_rgb.push_back((Uint32)(i<<16));
}
//selected ellipse not pure red at all!
char buf[100];
std::string ellipse=it->second.type().image_ellipse();
if(ellipse.empty()){
ellipse="misc/ellipse";
}
snprintf(buf,sizeof(buf),"%s-%stop.png",ellipse.c_str(),selected);
ellipse_back.assign(image::get_image(image::locator(buf,it->second.team_rgb_range(),temp_rgb)));
snprintf(buf,sizeof(buf),"%s-%sbottom.png",ellipse.c_str(),selected);
ellipse_front.assign(image::get_image(image::locator(buf,it->second.team_rgb_range(),temp_rgb)));
}
draw_unit(xpos,ypos - height_adjust,unit_image,false,
highlight_ratio,blend_with,blend_ratio,submerge,ellipse_back,ellipse_front);
}
const fixed_t bar_alpha = highlight_ratio < ftofxp(1.0) && blend_with == 0 ? highlight_ratio : (loc == mouseoverHex_ ? ftofxp(1.0): ftofxp(0.7));
draw_bar(*movement_file,xpos,ypos,0,0,energy_colour,bar_alpha);
draw_bar(*energy_file,xpos-5,ypos,(u.max_hitpoints()*2)/3,unit_energy,energy_colour,bar_alpha);
if(u.experience() > 0 && u.can_advance()) {
const double filled = double(u.experience())/double(u.max_experience());
const int level = maximum<int>(u.type().level(),1);
SDL_Color colour=u.xp_color();
draw_bar(*energy_file,xpos,ypos,u.max_experience()/(level*2),filled,colour,bar_alpha);
}
if (u.can_recruit()) {
surface crown(image::get_image("misc/leader-crown.png",image::SCALED,image::NO_ADJUST_COLOUR));
if(!crown.null()) {
//if(bar_alpha != ftofxp(1.0)) {
// crown = adjust_surface_alpha(crown, bar_alpha);
//}
SDL_Rect r = {0, 0, crown->w, crown->h};
video().blit_surface(xpos,ypos,crown,&r);
}
}
const std::vector<std::string>& overlays = it->second.overlays();
for(std::vector<std::string>::const_iterator ov = overlays.begin(); ov != overlays.end(); ++ov) {
const surface img(image::get_image(*ov));
if(img != NULL) {
draw_unit(xpos,ypos,img);
}
}
}
void display::draw_bar(const std::string& image, int xpos, int ypos, size_t height, double filled, const SDL_Color& col, fixed_t alpha)
@ -1541,7 +1331,7 @@ void display::draw_terrain_on_tile(int x, int y, image::TYPE image_type, ADJACEN
}
}
void display::draw_tile(int x, int y, surface unit_image, fixed_t alpha, Uint32 blend_to)
void display::draw_tile(int x, int y, double offset)
{
reach_map::iterator reach = reach_map_.end();
@ -1549,7 +1339,6 @@ void display::draw_tile(int x, int y, surface unit_image, fixed_t alpha, Uint32
return;
}
draw_halo_on_tile(x,y);
const gamemap::location loc(x,y);
int xpos = int(get_location_x(loc));
@ -1641,7 +1430,7 @@ void display::draw_tile(int x, int y, surface unit_image, fixed_t alpha, Uint32
}
draw_footstep(loc,xpos,ypos);
draw_unit_on_tile(x,y,unit_image,alpha,blend_to);
draw_unit_on_tile(x,y,offset);
if(!is_shrouded) {
draw_terrain_on_tile(x,y,image_type,ADJACENT_FOREGROUND);
@ -2298,12 +2087,6 @@ void display::set_playing_team(size_t team)
invalidate_game_status();
}
void display::set_advancing_unit(const gamemap::location& loc, double amount)
{
advancingUnit_ = loc;
advancingAmount_ = amount;
draw_tile(loc.x,loc.y);
}
bool display::turbo() const
{
@ -2474,7 +2257,7 @@ void display::add_chat_message(const std::string& speaker, int side, const std::
{
config* cignore;
bool ignored = false;
if (cignore = preferences::get_prefs()->child("ignore")){
if ((cignore = preferences::get_prefs()->child("ignore"))){
for(std::map<std::string,t_string>::const_iterator i = cignore->values.begin();
i != cignore->values.end(); ++i){
if(speaker == i->first){

View file

@ -58,7 +58,7 @@ public:
const config& cfg, const config& level);
~display();
Uint32 rgb(Uint8 red, Uint8 green, Uint8 blue);
static Uint32 rgb(Uint8 red, Uint8 green, Uint8 blue);
//new_turn should be called on every new turn, to update
//lighting settings.
@ -68,11 +68,6 @@ public:
//the map. Used for special effects like flashes.
void adjust_colours(int r, int g, int b);
//function to make it so a unit is 'hidden' - not displayed
//when the tile it is on is drawn. Only one unit may be hidden
//at a time. The previously hidden unit will be returned.
//'hide_energy' determines whether the unit's energy bar should be hidden too.
gamemap::location hide_unit(const gamemap::location& loc, bool hide_energy=false);
//function which scrolls the display by xmov,ymov. Invalidation and
//redrawing will be scheduled.
@ -142,6 +137,8 @@ public:
//and there is no unit in the currently highlighted hex, the unit will be
//displayed in the sidebar.
void select_hex(gamemap::location hex);
const gamemap::location& selected_hex() { return selectedHex_; }
const gamemap::location& mouseover_hex() { return mouseoverHex_; }
//function to highlight a location. If a unit is in the location, it will
//be displayed in the sidebar. Selection is used when a unit has been
@ -198,23 +195,21 @@ public:
//then it will be used, otherwise the unit's default image will be used.
//alpha controls how faded the unit is. If blend_to is not 0, then the
//unit will be alpha-blended to blend_to instead of the background colour
void draw_tile(int x, int y, surface unit_image=surface(NULL),
fixed_t alpha=ftofxp(1.0), Uint32 blend_to=0);
void draw_tile(int x, int y,double offset=0);
//function to float a label above a tile
void float_label(const gamemap::location& loc, const std::string& text,
int red, int green, int blue);
const gamemap& get_map() { return map_;}
private:
enum ADJACENT_TERRAIN_TYPE { ADJACENT_BACKGROUND, ADJACENT_FOREGROUND, ADJACENT_FOGSHROUD };
//composes and draws the terrains on a tile
void draw_terrain_on_tile(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE type);
void draw_unit_on_tile(int x, int y, surface unit_image=surface(NULL),
fixed_t alpha=ftofxp(1.0), Uint32 blend_to=0);
void draw_unit_on_tile(int x, int y,double offset);
void draw_halo_on_tile(int x, int y);
gui::button::TYPE string_to_button_type(std::string type);
@ -243,6 +238,7 @@ public:
//function to invalidate the game status displayed on the sidebar.
void invalidate_game_status();
const gamestatus &get_game_status() {return status_;};
//function to invalidate that unit status displayed on the sidebar.
void invalidate_unit();
@ -290,11 +286,9 @@ public:
//set_playing_team sets the team whose turn it currently is
void set_team(size_t team);
void set_playing_team(size_t team);
const std::vector<team>& get_teams() {return teams_;};
//makes it so that the unit at the given location will be displayed
//in an advancing-highlight with intensity between 0.0 and 1.0 given
//by amount.
void set_advancing_unit(const gamemap::location& loc, double amount);
const unit_map& get_units() {return units_;};
//compat methods to be dropped after full migration
void lock_updates(bool value) {screen_.lock_updates(value); };
@ -323,6 +317,7 @@ public:
//is the team whose turn it is
size_t viewing_team() const;
size_t playing_team() const;
bool team_valid() const;
theme& get_theme();
@ -378,6 +373,7 @@ public:
void begin_game();
bool in_game() const { return in_game_; }
void draw_bar(const std::string& image, int xpos, int ypos, size_t height, double filled, const SDL_Color& col, fixed_t alpha);
private:
display(const display&);
@ -415,7 +411,6 @@ private:
unit_map& units_;
void draw_bar(const std::string& image, int xpos, int ypos, size_t height, double filled, const SDL_Color& col, fixed_t alpha);
//function which finds the start and end rows on the energy bar image
//where white pixels are substituted for the colour of the energy
@ -429,7 +424,6 @@ private:
const gamestatus& status_;
bool team_valid() const;
const std::vector<team>& teams_;
@ -460,18 +454,8 @@ private:
size_t currentTeam_, activeTeam_;
//used to store a unit that is not drawn, because it's currently
//being moved or otherwise changed
gamemap::location hiddenUnit_;
bool hideEnergy_;
//used to store any unit that is dying
gamemap::location deadUnit_;
fixed_t deadAmount_;
//used to store any unit that is advancing
gamemap::location advancingUnit_;
double advancingAmount_;
bool turbo_, grid_;
double sidebarScaling_;
@ -510,9 +494,6 @@ private:
typedef std::map<gamemap::location,unsigned int> reach_map;
reach_map reach_map_;
typedef std::map<gamemap::location,int> halo_map;
halo_map haloes_;
//for debug mode
static std::map<gamemap::location,fixed_t> debugHighlights_;
@ -521,6 +502,7 @@ private:
int diagnostic_label_;
//animated flags for each team
//
std::vector<animated<image::locator> > flags_;
//the handle for the label which displays fps

View file

@ -246,10 +246,10 @@ private:
vconfig cfg_;
};
gamemap::location cfg_to_loc(const vconfig cfg)
gamemap::location cfg_to_loc(const vconfig cfg,int defaultx = 0, int defaulty = 0)
{
int x = lexical_cast_default(cfg["x"], 0) - 1;
int y = lexical_cast_default(cfg["y"], 0) - 1;
int x = lexical_cast_default(cfg["x"], defaultx) - 1;
int y = lexical_cast_default(cfg["y"], defaulty) - 1;
return gamemap::location(x, y);
}
@ -941,13 +941,21 @@ bool event_handler::handle_event_command(const queued_event& event_info,
//hiding units
else if(cmd == "hide_unit") {
const gamemap::location loc = cfg_to_loc(cfg);
screen->hide_unit(loc,true);
screen->draw_tile(loc.x,loc.y);
unit_map::iterator u = units->find(loc);
if(u != units->end()) {
u->second.set_hidden(true);
screen->draw_tile(loc.x,loc.y);
}
}
else if(cmd == "unhide_unit") {
const gamemap::location loc = screen->hide_unit(gamemap::location());
screen->draw_tile(loc.x,loc.y);
const gamemap::location loc = cfg_to_loc(cfg);
unit_map::iterator u;
// unhide all for backward compatibility
for(u = units->begin(); u != units->end() ; u++) {
u->second.set_hidden(false);
screen->draw_tile(loc.x,loc.y);
}
}
//adding new items
@ -1034,14 +1042,21 @@ bool event_handler::handle_event_command(const queued_event& event_info,
screen->invalidate(loc);
if (show) {
for(fixed_t alpha = ftofxp(0.0); alpha <= ftofxp(1.0); alpha += ftofxp(0.1)) {
events::pump();
screen->draw_tile(loc.x,loc.y,NULL,alpha);
unit_map::iterator un = units->find(loc);
if(show) {
un->second.set_recruited(screen->turbo()?5:1);
screen->scroll_to_tile(loc.x,loc.y,display::ONSCREEN);
while(!un->second.get_animation()->animation_finished()) {
screen->draw_tile(loc.x,loc.y);
screen->update_display();
SDL_Delay(20);
events::pump();
if(!screen->turbo()) SDL_Delay(10);
}
}
un->second.set_standing(screen->turbo()?5:1);
} else {
player_info* const player = state_of_game->get_player((*teams)[new_unit.side()-1].save_id());
@ -1306,7 +1321,7 @@ bool event_handler::handle_event_command(const queued_event& event_info,
if(game_events::unit_matches_filter(un,cfg)) {
if(cfg["animate"] == "yes") {
screen->scroll_to_tile(un->first.x,un->first.y);
unit_display::unit_die(*screen,un->first,un->second);
unit_display::unit_die(*screen,*game_map,un->first,un->second);
}
if(cfg["fire_event"] == "yes") {
@ -1560,33 +1575,18 @@ bool event_handler::handle_event_command(const queued_event& event_info,
screen->highlight_hex(u->first);
screen->scroll_to_tile(u->first.x,u->first.y);
surface unit_image(NULL);
const unit_animation* const anim_ptr = u->second.type().extra_animation(cfg["flag"]);
if(anim_ptr != NULL) {
unit_animation anim(*anim_ptr);
anim.start_animation(anim.get_first_frame_time(),1,screen->turbo() ? 5:1);
anim.update_current_frame();
while(!anim.animation_finished()) {
const unit_frame& frame = anim.get_current_frame();
const surface surf(image::get_image(frame.image));
if(surf.get() != NULL) {
unit_image = surf;
}
screen->draw_tile(u->first.x,u->first.y,unit_image);
screen->update_display();
SDL_Delay(10);
anim.update_current_frame();
}
unit_image = image::get_image(u->second.image_loc());
screen->draw_tile(u->first.x,u->first.y,unit_image);
u->second.set_extra_anim(cfg["flag"],screen->turbo()?5:1);
while(!u->second.get_animation()->animation_finished()) {
screen->draw_tile(u->first.x,u->first.y);
screen->update_display();
events::pump();
if(!screen->turbo()) SDL_Delay(10);
}
u->second.set_standing(screen->turbo()?5:1);
screen->draw_tile(u->first.x,u->first.y);
screen->update_display();
events::pump();
}
} else if(cmd == "label") {
const gamemap::location loc(lexical_cast_default<int>(cfg["x"],-1),lexical_cast_default<int>(cfg["y"],-1));

View file

@ -50,7 +50,7 @@ player_info* game_state::get_player(const std::string& id) {
time_of_day::time_of_day(const config& cfg)
: lawful_bonus(atoi(cfg["lawful_bonus"].c_str())),
image(cfg["image"]), name(cfg["name"]), id(cfg["id"]),
image_mask(cfg["mask"]),lighter_id(cfg["lighter"]),darker_id(cfg["darker"]),lighter(NULL),darker(NULL),
lighter_id(cfg["lighter"]),darker_id(cfg["darker"]),lighter(NULL),darker(NULL),image_mask(cfg["mask"]),
red(atoi(cfg["red"].c_str())),
green(atoi(cfg["green"].c_str())),
blue(atoi(cfg["blue"].c_str()))

View file

@ -145,6 +145,27 @@ gamemap::location::DIRECTION gamemap::location::parse_direction(const std::strin
}
}
std::string gamemap::location::write_direction(gamemap::location::DIRECTION dir)
{
switch(dir) {
case NORTH:
return std::string("n");
case NORTH_EAST:
return std::string("ne");
case NORTH_WEST:
return std::string("nw");
case SOUTH:
return std::string("s");
case SOUTH_EAST:
return std::string("se");
case SOUTH_WEST:
return std::string("sw");
default:
return std::string();
}
}
gamemap::location::location(const config& cfg) : x(-1), y(-1)
{
const std::string& xstr = cfg["x"];

View file

@ -64,6 +64,7 @@ public:
SOUTH_WEST, NORTH_WEST, NDIRECTIONS };
static DIRECTION parse_direction(const std::string& str);
static std::string write_direction(DIRECTION dir);
location() : x(-1), y(-1) {}
location(int x, int y) : x(x), y(y) {}

View file

@ -1510,9 +1510,9 @@ void turn_info::undo()
unit un = u->second;
un.set_goto(gamemap::location());
gui_.hide_unit(u->first,true);
u->second.set_hidden(true);
unit_display::move_unit(gui_,map_,route,un,status_.get_time_of_day(),units_,teams_);
gui_.hide_unit(gamemap::location());
u->second.set_hidden(false);
units_.erase(u);
un.set_movement(starting_moves);
@ -1598,9 +1598,9 @@ void turn_info::redo()
unit un = u->second;
un.set_goto(gamemap::location());
gui_.hide_unit(u->first,true);
u->second.set_hidden(true);
unit_display::move_unit(gui_,map_,route,un,status_.get_time_of_day(),units_,teams_);
gui_.hide_unit(gamemap::location());
u->second.set_hidden(false);
units_.erase(u);
un.set_movement(starting_moves);

View file

@ -301,7 +301,7 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
return res;
}
case UNIT_IMAGE:
return report("",u->second.image_loc(),"");
return report("",u->second.type().image(),"");
case UNIT_PROFILE:
return report("",u->second.type().image_profile(),"");
case TIME_OF_DAY: {

View file

@ -27,6 +27,9 @@
#include "serialization/string_utils.hpp"
#include "halo.hpp"
#include "display.hpp"
#include "gamestatus.hpp"
#include "actions.hpp"
#include "sound.hpp"
//DEBUG
#include <iostream>
@ -69,10 +72,10 @@ void sort_units(std::vector< unit > &units)
//constructor for reading a unit
unit::unit(const game_data& data, const config& cfg) :
state_(STATE_STANDING),
moves_(0), user_end_turn_(false), facingLeft_(true),
moves_(0), user_end_turn_(false), facing_(gamemap::location::NORTH_EAST),
resting_(false), hold_position_(false), recruit_(false),
guardian_(false), upkeep_(UPKEEP_FREE),anim_(NULL),user_image_(""),
unit_halo_(0),unit_anim_halo_(0)
unit_halo_(0),unit_anim_halo_(0),refreshing_(false),hidden_(false)
{
read(data,cfg);
@ -98,15 +101,15 @@ unit::unit(const unit_type* t, int side, bool use_traits, bool dummy_unit, unit_
maxExperience_(type_->experience_needed()),
backupMaxExperience_(type_->experience_needed()),
side_(side), moves_(0),
user_end_turn_(false), facingLeft_(side != 1),
user_end_turn_(false), facing_(gamemap::location::NORTH_EAST),
maxMovement_(type_->movement()),
backupMaxMovement_(type_->movement()),
resting_(false), hold_position_(false), recruit_(false),
attacks_(type_->attacks()),
backupAttacks_(type_->attacks()),
guardian_(false), upkeep_(UPKEEP_FULL_PRICE),
unrenamable_(false),anim_(NULL),unit_halo_(0),user_image_(""),
unit_anim_halo_(0)
unrenamable_(false),anim_(NULL),user_image_(""),unit_halo_(0),
unit_anim_halo_(0),refreshing_(false),hidden_(false)
{
//dummy units used by the 'move_unit_fake' command don't need to have a side.
if(dummy_unit == false) validate_side(side_);
@ -134,21 +137,21 @@ unit::unit(const unit_type* t, const unit& u) :
maxExperience_(type_->experience_needed()),
backupMaxExperience_(type_->experience_needed()),
side_(u.side()), moves_(u.moves_),
user_end_turn_(false), facingLeft_(u.facingLeft_),
user_end_turn_(false), facing_(u.facing_),
maxMovement_(type_->movement()),
backupMaxMovement_(type_->movement()),
resting_(u.resting_), hold_position_(u.hold_position_),
underlying_description_(u.underlying_description_),
profile_(u.profile_),
description_(u.description_), recruit_(u.recruit_),
description_(u.description_),profile_(u.profile_),
recruit_(u.recruit_),
role_(u.role_), statusFlags_(u.statusFlags_),
overlays_(u.overlays_), variables_(u.variables_),
attacks_(type_->attacks()), backupAttacks_(type_->attacks()),
modifications_(u.modifications_),
traitsDescription_(u.traitsDescription_),
guardian_(false), upkeep_(u.upkeep_),
unrenamable_(u.unrenamable_),anim_(NULL),unit_halo_(0),user_image_(u.user_image_),
unit_anim_halo_(0)
unrenamable_(u.unrenamable_),anim_(NULL),user_image_(u.user_image_),unit_halo_(0),
unit_anim_halo_(0),refreshing_(false),hidden_(false)
{
validate_side(side_);
@ -165,6 +168,10 @@ unit::~unit()
if(unit_halo_) {
halo::remove(unit_halo_);
}
if(unit_anim_halo_) {
halo::remove(unit_anim_halo_);
}
if(anim_) delete anim_;
}
void unit::generate_traits()
{
@ -539,9 +546,6 @@ void unit::heal_all()
hitpoints_ = max_hitpoints();
}
static bool is_terrain(std::string const &terrain, gamemap::TERRAIN type) {
return std::count(terrain.begin(), terrain.end(), static_cast<gamemap::TERRAIN>(type)) != 0;
}
bool unit::invisible(const std::string& terrain, int lawful_bonus,
const gamemap::location& loc,
@ -828,11 +832,8 @@ void unit::read(const game_data& data, const config& cfg)
upkeep_ = UPKEEP_FREE;
}
const std::string& facing = cfg["facing"];
if(facing == "reverse")
facingLeft_ = false;
else
facingLeft_ = true;
facing_ = gamemap::location::parse_direction(cfg["facing"]);
if(facing_ == gamemap::location::NDIRECTIONS) facing_ = gamemap::location::NORTH_EAST;
const std::string& ai_special = cfg["ai_special"];
if(ai_special == "guardian") {
@ -944,7 +945,7 @@ void unit::write(config& cfg) const
cfg.add_child("modifications",modifications_);
cfg["facing"] = facingLeft_ ? "normal" : "reverse";
cfg["facing"] = gamemap::location::write_direction(facing_);
switch(upkeep_) {
case UPKEEP_FULL_PRICE: cfg["upkeep"] = "full"; break;
@ -1002,121 +1003,279 @@ int unit::damage_against(const attack_type& attack) const
return type_->movement_type().damage_against(attack);
}
const std::string& unit::image() const
const surface unit::still_image() const
{
switch(state_) {
case STATE_STANDING:
if(! user_image_.empty()) {
return user_image_;
}
return type_->image();
case STATE_WALKING:
case STATE_DEFENDING: {
const std::string& res = anim_->get_current_frame().image;
if(res != "") {
return res;
} else {
if(anim_->animation_finished())
return anim_->get_last_frame().image;
else
return anim_->get_first_frame().image;
}
}
case STATE_ATTACKING: {
if(attackType_ == NULL)
return type_->image();
const std::string& img = attackType_->animation(true).first->get_current_frame().image;
if (img.empty())
return type_->image_fighting(attackType_->range_type());
else
return img;
}
case STATE_HEALING:
return type_->image_healing();
case STATE_LEADING:
return type_->image_leading();
default: return type_->image();
image::locator loc;
if(type().flag_rgb().size()){
loc = image::locator(absolute_image(),team_rgb_range(),type().flag_rgb());
}else{
loc = image::locator(absolute_image());
}
surface unit_image(image::get_image(loc,image::UNSCALED));
return unit_image;
}
const image::locator unit::image_loc() const
{
if(type().flag_rgb().size()){
return(image::locator(image(),team_rgb_range(),type().flag_rgb()));
}else{
return(image::locator(image()));
}
}
void unit::set_standing()
void unit::set_standing(int acceleration)
{
state_ = STATE_STANDING;
if(anim_) {
delete anim_;
anim_ = NULL;
}
if(!user_image_.empty()) {
anim_ = new unit_animation(user_image_);
} else {
anim_ = new unit_animation(type_->image());
}
anim_->start_animation(anim_->get_first_frame_time(),unit_animation::INFINITE_CYCLES,acceleration);
anim_->update_current_frame();
}
void unit::set_defending(bool hits, std::string range, int start_frame, int acceleration)
void unit::set_defending(int damage, std::string range, int acceleration)
{
update_frame();
state_ = STATE_DEFENDING;
if(anim_) {
delete anim_;
anim_ = NULL;
}
anim_ = new defensive_animation(type_->defend_animation(hits,range));
anim_->start_animation(start_frame,1,acceleration);
anim_->update_current_frame();
}
void unit::update_frame()
{
if (!anim_) return;
anim_->update_current_frame();
if( anim_->animation_finished()) {
delete anim_;
anim_ = NULL;
set_standing();
anim_ = new defensive_animation(type_->defend_animation(damage > 0?true:false,range));
// add a blink on damage effect
int anim_time = anim_->get_last_frame_time();
int damage_left = damage;
const std::string my_image = anim_->get_last_frame().image;
while(anim_time < 1000 && damage_left > 0 ) {
anim_->add_frame(anim_time,unit_frame(my_image,"",anim_time,anim_time+30,display::rgb(255,255,255),1.0));
anim_time += 30;
damage_left --;
anim_->add_frame(anim_time,unit_frame(my_image,"",anim_time,anim_time+30,display::rgb(255,255,255),0.0));
anim_time += 30;
damage_left --;
}
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_attacking( const attack_type* type, int ms)
void unit::set_extra_anim(std::string flag, int acceleration)
{
state_ = STATE_EXTRA;
if(anim_) {
delete anim_;
anim_ = NULL;
}
if(!type_->extra_animation(flag)) {
set_standing(acceleration);
return;
}
anim_ = new unit_animation(*(type_->extra_animation(flag)));
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
const unit_animation & unit::set_attacking(int acceleration,bool hit,const attack_type& type)
{
state_ = STATE_ATTACKING;
if(anim_) {
delete anim_;
anim_ = NULL;
}
attackType_ = type;
attackingMilliseconds_ = ms;
const attack_type::attack_animation &attack_anim = type.animation(hit,facing_) ;
anim_ = new unit_animation(attack_anim.animation);
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
return attack_anim.missile_animation;
}
void unit::set_leading()
void unit::set_leading(int acceleration)
{
state_ = STATE_LEADING;
if(anim_) {
delete anim_;
anim_ = NULL;
}
anim_ = new unit_animation(type().image_leading());
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_healing()
void unit::set_leveling_in(int acceleration)
{
state_ = STATE_LEVELIN;
if(anim_) {
delete anim_;
anim_ = NULL;
}
std::string my_image;
if(! user_image_.empty()) {
my_image = user_image_;
} else {
my_image = type_->image();
}
anim_ = new unit_animation();
// add a fade in effect
double blend_ratio =1;
int anim_time =0;
while(blend_ratio > 0) {
anim_->add_frame(anim_time,unit_frame(my_image,"",anim_time,anim_time+10,display::rgb(255,255,255),blend_ratio));
blend_ratio -=0.015;
anim_time += 10;
}
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_leveling_out(int acceleration)
{
state_ = STATE_LEVELOUT;
if(anim_) {
delete anim_;
anim_ = NULL;
}
std::string my_image;
if(! user_image_.empty()) {
my_image = user_image_;
} else {
my_image = type_->image();
}
anim_ = new unit_animation();
// add a fade out effect
double blend_ratio =0;
int anim_time =0;
while(blend_ratio < 1) {
anim_->add_frame(anim_time,unit_frame(my_image,"",anim_time,anim_time+10,display::rgb(255,255,255),blend_ratio));
blend_ratio +=0.015;
anim_time += 10;
}
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_recruited(int acceleration)
{
state_ = STATE_RECRUITED;
if(anim_) {
delete anim_;
anim_ = NULL;
}
anim_ = new unit_animation();
// add a fade in effect
double blend_ratio =0;
int anim_time =0;
while(blend_ratio < 1) {
anim_->add_frame(anim_time,unit_frame(type_->image(),"",anim_time,anim_time+10,0,0,ftofxp(blend_ratio)));
blend_ratio +=0.015;
anim_time += 10;
}
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_healed(int healing,int acceleration)
{
state_ = STATE_HEALED;
if(anim_) {
delete anim_;
anim_ = NULL;
}
anim_ = new unit_animation(type_->image());
// add a blink on heal effect
int anim_time = anim_->get_last_frame_time();
int heal_left = healing;
const std::string my_image = anim_->get_last_frame().image;
while(anim_time < 1000 && heal_left > 0 ) {
anim_->add_frame(anim_time,unit_frame(my_image,"",anim_time,anim_time+30,display::rgb(255,255,255),1.0));
anim_time += 30;
heal_left --;
anim_->add_frame(anim_time,unit_frame(my_image,"",anim_time,anim_time+30,display::rgb(255,255,255),0.0));
anim_time += 30;
heal_left --;
}
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_poisoned(int damage,int acceleration)
{
state_ = STATE_POISONED;
if(anim_) {
delete anim_;
anim_ = NULL;
}
anim_ = new unit_animation(type_->image());
// add a blink on damage effect
int anim_time = anim_->get_last_frame_time();
int damage_left = damage;
const std::string my_image = anim_->get_last_frame().image;
while(anim_time < 1000 && damage_left > 0 ) {
anim_->add_frame(anim_time,unit_frame(my_image,"",anim_time,anim_time+30,display::rgb(0,255,0),1.0));
anim_time += 30;
damage_left --;
anim_->add_frame(anim_time,unit_frame(my_image,"",anim_time,anim_time+30,display::rgb(0,255,0),0.0));
anim_time += 30;
damage_left --;
}
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_teleporting(int acceleration)
{
state_ = STATE_TELEPORT;
if(anim_) {
delete anim_;
anim_ = NULL;
}
anim_ = new unit_animation(type_->teleport_animation());
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_dying(const attack_type* attack, int acceleration)
{
state_ = STATE_DYING;
if(anim_) {
delete anim_;
anim_ = NULL;
}
anim_ = new death_animation(type_->die_animation(attack));
double blend_ratio = 1.0;
std::string tmp_image = anim_->get_last_frame().image;
int anim_time =anim_->get_last_frame_time();
while(blend_ratio > 0.0) {
anim_->add_frame(anim_time,unit_frame(tmp_image,"",anim_time,anim_time+10,0,0,ftofxp(blend_ratio)));
blend_ratio -=0.015;
anim_time += 10;
}
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_healing(int acceleration)
{
state_ = STATE_HEALING;
if(anim_) {
delete anim_;
anim_ = NULL;
}
int duration =0;
const std::vector<std::pair<std::string,int> > halos = unit_frame::prepare_halo(type().image_halo_healing(),0,0);
std::vector<std::pair<std::string,int> >::const_iterator cur_halo;
for(cur_halo = halos.begin() ; cur_halo != halos.end() ; cur_halo++) {
duration += cur_halo->second;
}
duration = maximum<int>(200,duration);
anim_ = new unit_animation(type().image_healing(),0,duration,"",type().image_halo_healing());
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
void unit::set_walking(const std::string terrain,gamemap::location::DIRECTION dir,int acceleration)
void unit::set_walking(const std::string terrain,int acceleration)
{
update_frame();
movement_animation* const anim = dynamic_cast<movement_animation*>(anim_);
if(state_ == STATE_WALKING && anim != NULL && anim->matches(terrain,dir) >=0) {
if(state_ == STATE_WALKING && anim != NULL && anim->matches(terrain,facing_) >=0) {
return; // finish current animation, don't start a new one
}
state_ = STATE_WALKING;
@ -1124,21 +1283,22 @@ void unit::set_walking(const std::string terrain,gamemap::location::DIRECTION di
delete anim_;
anim_ = NULL;
}
anim_ = new movement_animation(type_->move_animation(terrain,dir));
anim_ = new movement_animation(type_->move_animation(terrain,facing_));
anim_->start_animation(anim_->get_first_frame_time(),1,acceleration);
anim_->update_current_frame();
}
bool unit::facing_left() const
gamemap::location::DIRECTION unit::facing() const
{
return facingLeft_;
return facing_;
}
void unit::set_facing_left(bool newval)
void unit::set_facing(gamemap::location::DIRECTION dir)
{
facingLeft_ = newval;
wassert(dir != gamemap::location::NDIRECTIONS);
facing_ = dir;
}
const t_string& unit::traits_description() const
@ -1531,33 +1691,206 @@ bool unit::is_flying() const
return type().movement_type().is_flying();
}
void unit::refresh_unit(display& disp,const int& x, const int& y, const double& submerge)
void unit::restart_animation(int start_time, int acceleration) {
if(!anim_) return;
anim_->start_animation(start_time,1,acceleration);
}
void unit::refresh_unit(display& disp,gamemap::location hex,const int& x, const int& y,bool with_status)
{
gamemap::location hex = disp.hex_clicked_on(x+disp.hex_size()/2,y+disp.hex_size()/2);
gamemap::location adjacent[6];
get_adjacent_tiles(hex, adjacent);
surface image(image::get_image(image_loc()));
if (!facing_left()) {
image.assign(image::reverse_image(image));
const gamemap & map = disp.get_map();
if(hidden_) {
if(unit_halo_) halo::remove(unit_halo_);
unit_halo_ = 0;
if(unit_anim_halo_) halo::remove(unit_anim_halo_);
unit_anim_halo_ = 0;
return;
}
if(refreshing_) return;
if(disp.fogged(hex.x,hex.y)) { return;}
if(invisible(map.underlying_union_terrain(map[hex.x][hex.y]),
disp.get_game_status().get_time_of_day().lawful_bonus,hex,
disp.get_units(),disp.get_teams()) &&
disp.get_teams()[disp.playing_team()].is_enemy(side())) {
return;
}
refreshing_ = true;
gamemap::location adjacent[6];
get_adjacent_tiles(hex, adjacent);
if(!anim_) set_standing(disp.turbo()?5:1);
anim_->update_current_frame();
const gamemap::TERRAIN terrain = map.get_terrain(hex);
const double submerge = is_flying() ? 0.0 : map.get_terrain_info(terrain).unit_submerge();
const int height_adjust = is_flying() ? 0 : int(map.get_terrain_info(terrain).unit_height_adjust() * disp.zoom());
std::string image_name;
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 current_frame = anim_->get_current_frame();
image_name = current_frame.image;
if(anim_->frame_changed() ) {
if(!current_frame.sound.empty()) {
sound::play_sound(current_frame.sound);
}
disp.draw_tile(hex.x, hex.y);
}
if(unit_anim_halo_) halo::remove(unit_anim_halo_);
unit_anim_halo_ = 0;
if(!current_frame.halo.empty()) {
int time = current_frame.begin_time;
unsigned int sub_halo = 0;
while(time < anim_->get_animation_time()&& sub_halo < current_frame.halo.size()) {
time += current_frame.halo[sub_halo].second;
sub_halo++;
}
if(sub_halo >= current_frame.halo.size()) sub_halo = current_frame.halo.size() -1;
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-current_frame.halo_x,
y-current_frame.halo_y,
current_frame.halo[sub_halo].first);
} else {
const int d = disp.hex_size() / 2;
unit_anim_halo_ = halo::add(x+d+current_frame.halo_x,
y-current_frame.halo_y,
current_frame.halo[sub_halo].first,
halo::REVERSE);
}
}
if(image_name.empty()) {
image_name = type_->image();
}
image::locator loc;
if(type().flag_rgb().size()){
loc = image::locator(image_name,team_rgb_range(),type().flag_rgb());
}else{
loc = image::locator(image_name);
}
surface image(image::get_image(loc,stone()?image::GREYED : image::UNSCALED));
if(facing_ == gamemap::location::NORTH_WEST || facing_ == gamemap::location::SOUTH_WEST) {
image.assign(image::reverse_image(image));
}
Uint32 blend_with = current_frame.blend_with;
double blend_ratio = current_frame.blend_ratio;
fixed_t highlight_ratio = minimum<fixed_t>(type().alpha(),current_frame.highlight_ratio);
if(invisible(map.underlying_union_terrain(map[hex.x][hex.y]),
disp.get_game_status().get_time_of_day().lawful_bonus,hex,
disp.get_units(),disp.get_teams()) &&
highlight_ratio > ftofxp(0.5)) {
highlight_ratio = ftofxp(0.5);
}
if(hex == disp.selected_hex() && highlight_ratio == ftofxp(1.0)) {
highlight_ratio = ftofxp(1.5);
}
if (poisoned() && blend_ratio == 0){
blend_with = disp.rgb(0,255,0);
blend_ratio = 0.25;
}
surface ellipse_front(NULL);
surface ellipse_back(NULL);
if(preferences::show_side_colours() && with_status) {
const char* const selected = disp.selected_hex() == hex ? "selected-" : "";
std::vector<Uint32> temp_rgb;
//ellipse not pure red=255!
for(int i=255;i>100;i--){
temp_rgb.push_back((Uint32)(i<<16));
}
//selected ellipse not pure red at all!
char buf[100];
std::string ellipse=type().image_ellipse();
if(ellipse.empty()){
ellipse="misc/ellipse";
}
snprintf(buf,sizeof(buf),"%s-%stop.png",ellipse.c_str(),selected);
ellipse_back.assign(image::get_image(image::locator(buf,team_rgb_range(),temp_rgb)));
snprintf(buf,sizeof(buf),"%s-%sbottom.png",ellipse.c_str(),selected);
ellipse_front.assign(image::get_image(image::locator(buf,team_rgb_range(),temp_rgb)));
}
disp.draw_tile(hex.x, hex.y);
if(state_ != STATE_STANDING) {
for(int tile = 0; tile != 6; ++tile) {
disp.draw_tile(adjacent[tile].x, adjacent[tile].y);
}
disp.draw_unit(x, y, image, false, ftofxp(1.0), 0, 0.0, submerge);
if(!unit_halo_ && !type().image_halo().empty()) {
unit_halo_ = halo::add(0,0,type().image_halo());
}
disp.draw_unit(x, y -height_adjust, image, false, highlight_ratio,
blend_with, blend_ratio, submerge,ellipse_back,ellipse_front);
if(!unit_halo_ && !type().image_halo().empty()) {
unit_halo_ = halo::add(0,0,type().image_halo());
}
if(unit_halo_) {
const int d = disp.hex_size() / 2;
halo::set_location(unit_halo_, x+ d, y -height_adjust+ d);
}
if(with_status) {
const std::string* movement_file = NULL;
const std::string* energy_file = &game_config::energy_image;
const fixed_t bar_alpha = highlight_ratio < ftofxp(1.0) && blend_with == 0 ? highlight_ratio : (hex == disp.mouseover_hex() ? ftofxp(1.0): ftofxp(0.7));
if(size_t(side()) != disp.playing_team()+1) {
if(disp.team_valid() &&
disp.get_teams()[disp.playing_team()].is_enemy(side())) {
movement_file = &game_config::enemy_ball_image;
} else {
movement_file = &game_config::ally_ball_image;
}
} else {
if(disp.playing_team() == disp.playing_team() && movement_left() == total_movement() && !user_end_turn()) {
movement_file = &game_config::unmoved_ball_image;
} else if(disp.playing_team() == disp.playing_team() && unit_can_move(hex,disp.get_units(),map,disp.get_teams()) && !user_end_turn()) {
movement_file = &game_config::partmoved_ball_image;
} else {
movement_file = &game_config::moved_ball_image;
}
}
if(unit_halo_) {
int d = disp.hex_size() / 2;
halo::set_location(unit_halo_, x+ d, y+ d);
disp.draw_bar(*movement_file,x,y-height_adjust,0,0,hp_color(),bar_alpha);
double unit_energy = 0.0;
if(max_hitpoints() > 0) {
unit_energy = double(hitpoints())/double(max_hitpoints());
}
disp.draw_bar(*energy_file,x-5,y-height_adjust,(max_hitpoints()*2)/3,unit_energy,hp_color(),bar_alpha);
if(experience() > 0 && can_advance()) {
const double filled = double(experience())/double(max_experience());
const int level = maximum<int>(type().level(),1);
SDL_Color colour=xp_color();
disp.draw_bar(*energy_file,x,y-height_adjust,max_experience()/(level*2),filled,colour,bar_alpha);
}
if (can_recruit()) {
surface crown(image::get_image("misc/leader-crown.png",image::SCALED,image::NO_ADJUST_COLOUR));
if(!crown.null()) {
//if(bar_alpha != ftofxp(1.0)) {
// crown = adjust_surface_alpha(crown, bar_alpha);
//}
SDL_Rect r = {0, 0, crown->w, crown->h};
disp.video().blit_surface(x,y-height_adjust,crown,&r);
}
}
disp.update_display();
events::pump();
}
for(std::vector<std::string>::const_iterator ov = overlays().begin(); ov != overlays().end(); ++ov) {
const surface img(image::get_image(*ov));
if(img != NULL) {
disp.draw_unit(x,y-height_adjust,img);
}
}
refreshing_ = false;
}

View file

@ -34,7 +34,8 @@ class unit
public:
friend struct unit_movement_resetter;
unit(const unit& u) { *this=u ; unit_halo_ = 0; }
//unit(const unit& u) { *this=u ; unit_halo_ = 0; unit_anim_halo_ = 0; anim_ =new unit_animation(*u.anim_);}
unit(const unit& u) { *this=u ; unit_halo_ = 0; unit_anim_halo_ = 0; anim_ =NULL; }
unit(const game_data& data, const config& cfg);
unit(const unit_type* t, int side, bool use_traits=false, bool dummy_unit=false, unit_race::GENDER gender=unit_race::MALE);
@ -136,23 +137,31 @@ public:
int defense_modifier(const gamemap& map, gamemap::TERRAIN terrain) const;
int damage_against(const attack_type& attack) const;
//gets the unit image that should currently be displayed
//(could be in the middle of an attack etc)
//the name of the file to display (used in menus
const std::string& absolute_image() const {return type_->image();}
const image::locator image_loc() const;
void refresh_unit(display& disp,const int& x,const int& y,const double& submerge);
// a sdl surface, ready for display for place where we need a fix image of the unit
const surface still_image() const;
void refresh_unit(display& disp,gamemap::location hex,const int& x,const int& y, bool with_status =false);
void set_standing();
void set_defending(bool hits, std::string range, int start_frame, int acceleration);
void update_frame();
void set_attacking( const attack_type* type=NULL, int ms=0);
void set_standing(int acceleration);
void set_defending(int damage, std::string range, int acceleration);
void set_leading(int acceleration);
void set_healing(int acceleration);
void set_leveling_in(int acceleration);
void set_leveling_out(int acceleration);
void set_teleporting (int acceleration);
void set_extra_anim(std::string flag, int acceleration);
void set_dying(const attack_type *attack, int acceleration);
void set_walking(const std::string terrain,int acceleration);
const unit_animation & set_attacking(int acceleration,bool hit,const attack_type& type);
void set_recruited(int acceleration);
void set_healed(int healing,int acceleration);
void set_poisoned(int damage,int acceleration);
void restart_animation(int start_time, int acceleration);
const unit_animation* get_animation() const { return anim_;};
void set_leading();
void set_healing();
void set_walking(const std::string terrain,gamemap::location::DIRECTION,int acceleration);
bool facing_left() const;
void set_facing_left(bool newval);
void set_facing(gamemap::location::DIRECTION);
gamemap::location::DIRECTION facing() const;
const t_string& traits_description() const;
@ -164,6 +173,7 @@ public:
int upkeep() const;
void set_hidden(bool state) {hidden_ = state;};
bool is_flying() const;
bool can_advance() const;
@ -188,7 +198,9 @@ public:
// NOT_MOVED if not moved and pressed "end turn"
enum MOVES { ATTACKED=-1, MOVED=-2, NOT_MOVED=-3 };
enum STATE { STATE_STANDING, STATE_ATTACKING, STATE_DEFENDING,
STATE_LEADING, STATE_HEALING, STATE_WALKING};
STATE_LEADING, STATE_HEALING, STATE_WALKING, STATE_LEVELIN,
STATE_LEVELOUT, STATE_DYING, STATE_EXTRA, STATE_TELEPORT,
STATE_RECRUITED, STATE_HEALED, STATE_POISONED};
STATE state() const {return state_;}
private:
const std::string& image() const;
@ -199,8 +211,6 @@ private:
const unit_type* type_;
STATE state_;
const attack_type* attackType_;
int attackingMilliseconds_;
bool getsHit_;
int hitpoints_;
@ -212,7 +222,7 @@ private:
int moves_;
bool user_end_turn_;
bool facingLeft_;
gamemap::location::DIRECTION facing_;
int maxMovement_, backupMaxMovement_;
bool resting_;
bool hold_position_;
@ -263,6 +273,8 @@ private:
void generate_traits_description();
int unit_halo_;
int unit_anim_halo_;
bool refreshing_; // avoid infinit recursion
bool hidden_;
};

View file

@ -32,12 +32,41 @@ unit_frame::unit_frame(const config& cfg)
xoffset = atoi(cfg["xoffset"].c_str());
image = cfg["image"];
image_diagonal = cfg["image_diagonal"];
halo = cfg["halo"];
halo_x = atoi(cfg["halo_x"].c_str());
halo_y = atoi(cfg["halo_y"].c_str());
sound = cfg["sound"];
begin_time = atoi(cfg["begin"].c_str());
end_time = atoi(cfg["end"].c_str());
highlight_ratio = ftofxp(1);
halo = prepare_halo(cfg["halo"],begin_time,end_time);
}
std::vector<std::pair<std::string,int> > unit_frame::prepare_halo(const std::string & halo,int begin, int end)
{
const int duration = end - begin;
const std::vector<std::string> first_pass = utils::split(halo);
const int time_chunk = maximum<int>(duration / (first_pass.size()?first_pass.size():1),1);
std::vector<std::string>::const_iterator tmp;
std::vector<std::pair<std::string,int> > result;
for(tmp=first_pass.begin();tmp != first_pass.end() ; tmp++) {
std::vector<std::string> second_pass = utils::split(*tmp,':');
if(second_pass.size() > 1) {
result.push_back(std::pair<std::string,int>(second_pass[0],atoi(second_pass[1].c_str())));
} else {
result.push_back(std::pair<std::string,int>(second_pass[0],time_chunk));
}
}
return result;
}
unit_animation::unit_animation(const std::string image )
{
add_frame(0,unit_frame(image));
}
unit_animation::unit_animation(const config& cfg,const std::string frame_string )
{
config::const_child_itors range = cfg.child_range(frame_string);
@ -56,9 +85,9 @@ unit_animation::unit_animation(const config& cfg,const std::string frame_string
}
}
unit_animation::unit_animation(const std::string image, int begin_at, int end_at, const std::string image_diagonal)
unit_animation::unit_animation(const std::string image, int begin_at, int end_at, const std::string image_diagonal,const std::string halo)
{
add_frame(begin_at, unit_frame(image,image_diagonal));
add_frame(begin_at, unit_frame(image,image_diagonal,begin_at,end_at,0,0.0,ftofxp(1),halo));
add_frame(end_at);
}

View file

@ -24,18 +24,31 @@
//a class to describe a unit's animation sequence
struct unit_frame {
unit_frame() : xoffset(0), halo_x(0), halo_y(0) {}
explicit unit_frame(const std::string& str, const std::string & diag ="") : xoffset(0), image(str),image_diagonal(diag),
halo_x(0), halo_y(0) {};
explicit unit_frame(const config& cfg);
unit_frame() : xoffset(0), halo_x(0), halo_y(0), begin_time(0), end_time(0),highlight_ratio(ftofxp(1)){}
explicit unit_frame(const std::string& str, const std::string & diag ="",
int begin=0,int end = 0,
Uint32 blend_color = 0, double blend_rate = 0.0,
fixed_t highlight = ftofxp(1),
std::string in_halo = "") :
xoffset(0), image(str),image_diagonal(diag),
halo_x(0), halo_y(0),
begin_time(begin), end_time(end),
blend_with(blend_color), blend_ratio(blend_rate),
highlight_ratio(highlight) {halo = prepare_halo(in_halo,begin,end);};
explicit unit_frame(const config& cfg);
// int start, end;
int xoffset;
std::string image;
std::string image_diagonal;
std::string halo;
std::string sound;
int halo_x, halo_y;
// int start, end;
int xoffset;
std::string image;
std::string image_diagonal;
std::vector<std::pair<std::string,int> > halo;
std::string sound;
int halo_x, halo_y;
int begin_time, end_time;
Uint32 blend_with;
double blend_ratio;
fixed_t highlight_ratio;
static std::vector<std::pair<std::string,int> > prepare_halo(const std::string & halo,int begin, int end);
};
class unit_animation:public animated<unit_frame>
{
@ -43,7 +56,8 @@ 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 std::string image, int begin_at, int end_at, const std::string image_diagonal = "");
explicit unit_animation(const std::string image, int begin_at, int end_at, const std::string image_diagonal = "",const std::string halo="");
explicit unit_animation(const std::string image);
enum FRAME_DIRECTION { VERTICAL, DIAGONAL };

View file

@ -39,107 +39,30 @@ void teleport_unit_between(display& disp, const gamemap& map, const gamemap::loc
return;
}
const bool face_left = u.facing_left();
const int xsrc = disp.get_location_x(a);
const int ysrc = disp.get_location_y(a);
const int xdst = disp.get_location_x(b);
const int ydst = disp.get_location_y(b);
const gamemap::TERRAIN src_terrain = map.get_terrain(a);
const gamemap::TERRAIN dst_terrain = map.get_terrain(b);
const int src_height_adjust = u.is_flying() ? 0 : int(map.get_terrain_info(src_terrain).unit_height_adjust() * disp.zoom());
const int dst_height_adjust = u.is_flying() ? 0 : int(map.get_terrain_info(dst_terrain).unit_height_adjust() * disp.zoom());
const double src_submerge = u.is_flying() ? 0.0 : map.get_terrain_info(src_terrain).unit_submerge();
const double dst_submerge = u.is_flying() ? 0.0 : map.get_terrain_info(dst_terrain).unit_submerge();
LOG_DP << "submerge: " << src_submerge << " -> " << dst_submerge << "\n";
const int acceleration = disp.turbo() ? 5:1;
gamemap::location src_adjacent[6];
get_adjacent_tiles(a, src_adjacent);
gamemap::location dst_adjacent[6];
get_adjacent_tiles(b, dst_adjacent);
const std::string& halo = u.type().image_halo();
util::scoped_resource<int,halo::remover> halo_effect(0);
if(halo.empty() == false && !disp.fogged(b.x,b.y)) {
halo_effect.assign(halo::add(0,0,halo));
}
const unit_animation &teleport_animation_p = u.type().teleport_animation();
u.set_teleporting(disp.turbo()?5:1);
if (!disp.fogged(a.x, a.y)) { // teleport
unit_animation teleport_animation = teleport_animation_p;
int animation_time;
const int begin_at = teleport_animation.get_first_frame_time();
teleport_animation.start_animation(begin_at,1, acceleration);
animation_time = teleport_animation.get_animation_time();
disp.scroll_to_tile(a.x,a.y,display::ONSCREEN);
while(animation_time < 0) {
const std::string* unit_image = &teleport_animation.get_current_frame().image;
image::locator unit_loc;
if (unit_image->empty()) {
unit_loc = u.image_loc();
} else {
unit_loc = image::locator(*unit_image,u.team_rgb_range(),u.type().flag_rgb());
}
surface image(image::get_image(unit_loc));
if (!face_left) {
image.assign(image::reverse_image(image));
}
while(!u.get_animation()->animation_finished() && u.get_animation()->get_animation_time() < 0) {
disp.draw_tile(a.x,a.y);
for(int tile = 0; tile != 6; ++tile) {
disp.draw_tile(src_adjacent[tile].x, src_adjacent[tile].y);
}
disp.draw_unit(xsrc,ysrc - src_height_adjust,image,false, ftofxp(1.0), 0, 0.0, src_submerge);
disp.update_display();
events::pump();
teleport_animation.update_current_frame();
animation_time = teleport_animation.get_animation_time();
}
disp.draw_tile(a.x,a.y);
disp.update_display();
events::pump();
teleport_animation.update_current_frame();
}
if(!disp.turbo()) SDL_Delay(10);
}
}
if (!disp.fogged(b.x, b.y)) { // teleport
unit_animation teleport_animation = teleport_animation_p;
int animation_time;
const int end_at = teleport_animation.get_last_frame_time();
teleport_animation.start_animation(0,1, acceleration);
animation_time = teleport_animation.get_animation_time();
disp.scroll_to_tile(b.x,b.y,display::ONSCREEN);
while(animation_time < end_at) {
const std::string* unit_image = &teleport_animation.get_current_frame().image;
image::locator unit_loc;
if (unit_image->empty()) {
unit_loc = u.image_loc();
}else{
unit_loc = image::locator(*unit_image,u.team_rgb_range(),u.type().flag_rgb());
}
surface image(image::get_image(unit_loc));
if (!face_left) {
image.assign(image::reverse_image(image));
}
while(u.get_animation()->animation_finished()) {
disp.draw_tile(b.x,b.y);
for(int tile = 0; tile != 6; ++tile) {
disp.draw_tile(dst_adjacent[tile].x,dst_adjacent[tile].y);
}
disp.draw_unit(xdst, ydst - dst_height_adjust, image, false, ftofxp(1.0), 0, 0.0, dst_submerge);
disp.update_display();
events::pump();
teleport_animation.update_current_frame();
animation_time = teleport_animation.get_animation_time();
if(!disp.turbo()) SDL_Delay(10);
}
}
u.set_standing(disp.turbo()?5:1);
disp.update_display();
events::pump();
}
@ -150,22 +73,9 @@ void move_unit_between(display& disp, const gamemap& map, const gamemap::locatio
return;
}
const int xsrc = disp.get_location_x(a);
const int ysrc = disp.get_location_y(a);
const int xdst = disp.get_location_x(b);
const int ydst = disp.get_location_y(b);
const gamemap::TERRAIN src_terrain = map.get_terrain(a);
const gamemap::TERRAIN dst_terrain = map.get_terrain(b);
const int src_height_adjust = u.is_flying() ? 0 : int(map.get_terrain_info(src_terrain).unit_height_adjust() * disp.zoom());
const int dst_height_adjust = u.is_flying() ? 0 : int(map.get_terrain_info(dst_terrain).unit_height_adjust() * disp.zoom());
const double src_submerge = u.is_flying() ? 0.0 : map.get_terrain_info(src_terrain).unit_submerge();
const double dst_submerge = u.is_flying() ? 0.0 : map.get_terrain_info(dst_terrain).unit_submerge();
LOG_DP << "submerge: " << src_submerge << " -> " << dst_submerge << "\n";
const int acceleration = disp.turbo() ? 5:1;
gamemap::location src_adjacent[6];
@ -174,24 +84,24 @@ void move_unit_between(display& disp, const gamemap& map, const gamemap::locatio
gamemap::location dst_adjacent[6];
get_adjacent_tiles(b, dst_adjacent);
const std::string& halo = u.type().image_halo();
util::scoped_resource<int,halo::remover> halo_effect(0);
if(halo.empty() == false && !disp.fogged(b.x,b.y)) {
halo_effect.assign(halo::add(0,0,halo));
}
const int total_mvt_time = 150 * u.movement_cost(map,dst_terrain)/acceleration;
const unsigned int start_time = SDL_GetTicks();
int mvt_time = SDL_GetTicks() -start_time;
disp.scroll_to_tiles(a.x,a.y,b.x,b.y,display::ONSCREEN);
const double xsrc = disp.get_location_x(a);
const double ysrc = disp.get_location_y(a);
const double xdst = disp.get_location_x(b);
const double ydst = disp.get_location_y(b);
while(mvt_time < total_mvt_time) {
u.set_walking(map.underlying_mvt_terrain(src_terrain),a.get_relative_dir(b),acceleration);
const int height_adjust = src_height_adjust + int(double(dst_height_adjust - src_height_adjust) * (double(mvt_time) / total_mvt_time));
const double submerge = src_submerge + int(double(dst_submerge - src_submerge) * (double(mvt_time) / total_mvt_time));
const int xloc = xsrc + int(double(xdst-xsrc)*(double(mvt_time)/total_mvt_time));
const int yloc = ysrc + int(double(ydst-ysrc)*(double(mvt_time)/total_mvt_time)) - height_adjust;
u.refresh_unit(disp,xloc,yloc,submerge);
u.set_walking(map.underlying_mvt_terrain(src_terrain),acceleration);
const double pos =double(mvt_time)/total_mvt_time;
const int posx = int(pos*xdst + (1.0-pos)*xsrc);
const int posy = int(pos*ydst + (1.0-pos)*ysrc);
disp.draw_tile(a.x,a.y);
u.refresh_unit(disp,a,posx,posy);
disp.update_display();
events::pump();
if(!disp.turbo()) SDL_Delay(10);
mvt_time = SDL_GetTicks() -start_time;
}
@ -220,11 +130,7 @@ void move_unit(display& disp, const gamemap& map, const std::vector<gamemap::loc
{
bool previous_visible = false;
for(size_t i = 0; i+1 < path.size(); ++i) {
if(path[i+1].x > path[i].x) {
u.set_facing_left(true);
} else if(path[i+1].x < path[i].x) {
u.set_facing_left(false);
}
u.set_facing(path[i].get_relative_dir(path[i+1]));
disp.remove_footstep(path[i]);
@ -249,7 +155,7 @@ void move_unit(display& disp, const gamemap& map, const std::vector<gamemap::loc
disp.draw_tile(path[i].x,path[i].y);
}
}
u.set_standing();
u.set_standing(disp.turbo()?5:1);
//make sure the entire path is cleaned properly
for(std::vector<gamemap::location>::const_iterator it = path.begin(); it != path.end(); ++it) {
@ -257,7 +163,7 @@ void move_unit(display& disp, const gamemap& map, const std::vector<gamemap::loc
}
}
void unit_die(display& disp, const gamemap::location& loc, const unit& u, const attack_type* attack)
void unit_die(display& disp, const gamemap &map,const gamemap::location& loc, unit& u, const attack_type* attack)
{
if(disp.update_locked() || disp.fogged(loc.x,loc.y) || preferences::show_combat() == false) {
return;
@ -267,342 +173,146 @@ void unit_die(display& disp, const gamemap::location& loc, const unit& u, const
if(die_sound != "" && die_sound != "null") {
sound::play_sound(die_sound);
}
u.set_dying(attack,disp.turbo() ? 5:1);
surface unit_image(NULL);
unit_animation anim(u.type().die_animation(attack));
while(!u.get_animation()->animation_finished()) {
anim.start_animation(anim.get_first_frame_time(),1,disp.turbo() ? 5:1);
anim.update_current_frame();
while(!anim.animation_finished()) {
const unit_frame& frame = anim.get_current_frame();
const surface surf(image::get_image(image::locator(frame.image,u.team_rgb_range(), u.type().flag_rgb())));
if(surf.get() != NULL) {
unit_image = surf;
}
disp.draw_tile(loc.x,loc.y,unit_image);
disp.draw_tile(loc.x,loc.y);
disp.update_display();
SDL_Delay(10);
anim.update_current_frame();
events::pump();
if(!disp.turbo()) SDL_Delay(10);
}
const int frame_time = 30;
int ticks = SDL_GetTicks();
for(fixed_t alpha = ftofxp(1.0); alpha > ftofxp(0.0); alpha -= ftofxp(0.05)) {
disp.draw_tile(loc.x,loc.y,unit_image,alpha);
const int wait_time = ticks + frame_time - SDL_GetTicks();
if(wait_time > 0 && !disp.turbo())
SDL_Delay(wait_time);
ticks = SDL_GetTicks();
disp.update_display();
}
disp.draw_tile(loc.x,loc.y,unit_image,ftofxp(0.0));
u.set_standing(disp.turbo() ? 5:1);
disp.update_display();
events::pump();
}
namespace {
bool unit_attack_ranged(display& disp, unit_map& units,
bool unit_attack_ranged(display& disp,const gamemap& map, unit_map& units,
const gamemap::location& a, const gamemap::location& b,
int damage, const attack_type& attack, bool update_display)
int damage, const attack_type& attack, bool update_display)
{
const bool hide = disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y)
|| preferences::show_combat() == false || (!update_display);
|| preferences::show_combat() == false || (!update_display);
log_scope("unit_attack_range");
const unit_map::iterator att = units.find(a);
const unit_map::iterator def = units.find(b);
wassert(att != units.end());
unit& attacker = att->second;
const gamemap::location leader_loc = under_leadership(units,a);
unit_map::iterator leader = units.end();
if(leader_loc.valid()) {
leader = units.find(leader_loc);
wassert(leader != units.end());
leader->second.set_leading();
}
const unit_map::iterator def = units.find(b);
wassert(def != units.end());
unit& defender = def->second;
const bool hits = damage > 0;
const std::pair<const unit_animation*,const unit_animation*> tmp_pair = attack.animation(hits,get_adjacent_direction(a,b)) ;
unit_animation attack_anim = *tmp_pair.first;
unit_animation missile_anim = *tmp_pair.second;
const int acceleration = disp.turbo() ? 5 : 1;
//the missile frames are based around the time when the missile impacts.
//the 'real' frames are based around the time when the missile launches.
const int first_missile = minimum<int>(-100,missile_anim.get_first_frame_time());
const int last_missile = missile_anim.get_last_frame_time();
const int real_last_missile = last_missile - first_missile;
const int missile_impact = -first_missile;
const int time_resolution = 20;
const int acceleration = disp.turbo() ? 5:1;
const std::string& hit_sound = def->second.type().get_hit_sound();
bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
const int play_hit_sound_at = 0;
const int begin_at = attack_anim.get_first_frame_time();
// more damage shown for longer, but 1s at most for this factor
const int end_at = maximum<int>(minimum<int>((damage+1)*time_resolution+missile_impact, 1000),
maximum(attack_anim.get_last_frame_time(),real_last_missile));
const double xsrc = disp.get_location_x(a);
const double ysrc = disp.get_location_y(a);
const double xdst = disp.get_location_x(b);
const double ydst = disp.get_location_y(b);
gamemap::location update_tiles[6];
get_adjacent_tiles(a,update_tiles);
get_adjacent_tiles(b,update_tiles);
bool dead = false;
// start leader and attacker animation, wait for attacker animation to end
unit_animation missile_animation = attacker.set_attacking(acceleration,hits,attack);
const gamemap::location leader_loc = under_leadership(units,a);
unit_map::iterator leader = units.end();
if(leader_loc.valid()){
LOG_DP << "found leader at " << leader_loc << '\n';
leader = units.find(leader_loc);
wassert(leader != units.end());
leader->second.set_leading(disp.turbo()?5:1);
}
while(!attacker.get_animation()->animation_finished() ) {
disp.draw_tile(a.x,a.y);
//if(leader_loc.valid()) leader->second.refresh_unit(disp,map,disp.get_location_x(leader_loc),disp.get_location_y(leader_loc));
disp.update_display();
events::pump();
if(!disp.turbo()) SDL_Delay(10);
}
int animation_time;
const bool vflip = b.y > a.y || b.y == a.y && is_even(a.x);
const bool hflip = b.x < a.x;
const unit_animation::FRAME_DIRECTION dir = (a.x == b.x) ? unit_animation::VERTICAL:unit_animation::DIAGONAL;
bool dead = false;
const int drain_speed = 1*acceleration;
int flash_num = 0;
bool shown_label = false;
util::scoped_resource<int,halo::remover> missile_halo_effect(0), unit_halo_effect(0);
const std::string* missile_halo_image = NULL;
const std::string* unit_halo_image = NULL;
int missile_halo_x = -1, missile_halo_y = -1, unit_halo_x = -1, unit_halo_y = -1;
attack_anim.start_animation(begin_at,1, acceleration);
missile_anim.start_animation(begin_at + first_missile,1, acceleration);
attack_anim.update_current_frame();
missile_anim.update_current_frame();
int animation_time = attack_anim.get_animation_time();
def->second.set_defending(hits, attack.range(), animation_time, acceleration);
while(animation_time < end_at && !hide) {
if(!hide && hits && !played_hit_sound && animation_time >= play_hit_sound_at) {
sound::play_sound(hit_sound);
played_hit_sound = true;
}
const unit_frame& attack_frame = attack_anim.get_current_frame();
if(attack_anim.frame_changed() && !attack_frame.sound.empty()) {
sound::play_sound(attack_frame.sound);
}
LOG_DP << "Animation time :" << animation_time << ", image " << attack_frame.image << "\n";
int new_halo_x = attack_frame.halo_x;
int new_halo_y = attack_frame.halo_y;
const std::string* unit_image = &attack_frame.image;
if(att->second.facing_left() == false) {
new_halo_x *= -1;
}
if(unit_halo_image != &attack_frame.halo ||
unit_halo_x != new_halo_x ||
unit_halo_y != new_halo_y) {
unit_halo_image = &attack_frame.halo;
unit_halo_x = new_halo_x;
unit_halo_y = new_halo_y;
if(!attack_frame.halo.empty() && !disp.fogged(a.x,a.y)) {
const int halo_xpos = int(disp.get_location_x(a) +
disp.hex_size()/2.0 + unit_halo_x*disp.zoom());
const int halo_ypos = int(disp.get_location_y(a) +
disp.hex_size()/2.0 + unit_halo_y*disp.zoom());
unit_halo_effect.assign(halo::add(halo_xpos,halo_ypos,*unit_halo_image));
} else {
unit_halo_effect.assign(0);
}
}
if(unit_image->empty()) {
unit_image = &att->second.type().image_fighting(attack_type::LONG_RANGE);
}
if(!hide) {
const surface image((unit_image == NULL) ? surface(NULL) : image::get_image(image::locator(*unit_image,att->second.team_rgb_range(),att->second.type().flag_rgb())));
disp.draw_tile(a.x,a.y,image);
}
if(damage > 0 && animation_time >= missile_impact && shown_label == false) {
shown_label = true;
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
}
Uint32 defensive_colour = 0;
fixed_t defensive_alpha = ftofxp(1.0);
LOG_DP << "Waiting for missile impact at " << missile_impact << "\n";
if(damage > 0 && animation_time >= missile_impact) {
if(def->second.gets_hit(minimum<int>(drain_speed,damage))) {
dead = true;
damage = 0;
} else {
damage -= drain_speed;
}
if(flash_num == 0 || flash_num == 2) {
defensive_alpha = ftofxp(0.0);
defensive_colour = disp.rgb(200,0,0);
}
++flash_num;
}
for(int j = 0; j != 6; ++j) {
if(update_tiles[j] != b) {
disp.draw_tile(update_tiles[j].x,update_tiles[j].y);
}
}
disp.draw_tile(b.x,b.y,NULL,defensive_alpha,defensive_colour);
if(leader_loc.valid()) {
disp.draw_tile(leader_loc.x,leader_loc.y);
}
if(animation_time >= 0 && animation_time < real_last_missile && !hide) {
const unit_frame& missile_frame = missile_anim.get_current_frame();
LOG_DP << "Missile: animation time :" << animation_time << ", image "
<< missile_frame.image << ", halo: " << missile_frame.halo << "\n";
new_halo_x = missile_frame.halo_x;
new_halo_y = missile_frame.halo_y;
if(att->second.facing_left() == false) {
new_halo_x *= -1;
}
new_halo_x = int(new_halo_x*disp.zoom());
new_halo_y = int(new_halo_y*disp.zoom());
defender.set_defending(damage,attack.range(),acceleration);
const int start_time = minimum<int>(minimum<int>(defender.get_animation()->get_first_frame_time(),
missile_animation.get_first_frame_time()),-200);
missile_animation.start_animation(start_time,acceleration);
defender.restart_animation(start_time,acceleration);
while(!defender.get_animation()->animation_finished() ||
(leader_loc.valid() && !leader->second.get_animation()->animation_finished())) {
const double pos = animation_time < defender.get_animation()->get_first_frame_time()?1.0:
double(animation_time)/double(attacker.get_animation()->get_first_frame_time());
const int posx = int(pos*xsrc + (1.0-pos)*xdst);
const int posy = int(pos*ysrc + (1.0-pos)*ydst);
disp.draw_tile(b.x,b.y);
disp.draw_tile(a.x,a.y);
//if(leader_loc.valid()) leader->second.refresh_unit(disp,leader_loc.x,leader_loc.y);
if(pos > 0.0 && pos < 1.0) {
const unit_frame& missile_frame = missile_animation.get_current_frame();
const std::string *missile_image = NULL;
if(dir == unit_animation::VERTICAL) {
missile_image = &missile_frame.image;
} else {
missile_image = &missile_frame.image_diagonal;
}
static const std::string default_missile(game_config::missile_n_image);
static const std::string default_diag_missile(game_config::missile_ne_image);
if(missile_image->empty()) {
if(dir == unit_animation::VERTICAL)
missile_image = &default_missile;
else
missile_image = &default_diag_missile;
}
surface img(image::get_image(image::locator(*missile_image)));
if(hflip) {
img.assign(image::reverse_image(img));
}
disp.draw_unit(posx, posy , img,vflip);
double pos = double(missile_impact - animation_time)/double(missile_impact);
if(pos < 0.0) {
pos = 0.0;
}
const int xpos = int((xsrc+new_halo_x)*pos + xdst*(1.0-pos));
const int ypos = int((ysrc+new_halo_y)*pos + ydst*(1.0-pos));
if(img != NULL) {
disp.draw_unit(xpos,ypos,img,vflip);
}
const int halo_xpos = xpos+disp.hex_size()/2;
const int halo_ypos = ypos+disp.hex_size()/2;
if(missile_halo_image != &missile_frame.halo || missile_halo_x != new_halo_x || missile_halo_y != new_halo_y) {
missile_halo_image = &missile_frame.halo;
missile_halo_x = new_halo_x;
missile_halo_y = new_halo_y;
if(missile_halo_image != NULL &&
!missile_halo_image->empty() &&
!disp.fogged(b.x,b.y)) {
missile_halo_effect.assign(halo::add(halo_xpos,halo_ypos,*missile_halo_image));
} else {
missile_halo_effect.assign(0);
}
}
else if(missile_halo_effect != 0) {
halo::set_location(missile_halo_effect,halo_xpos,halo_ypos);
}
} else {
//the missile halo should disappear now, since the missile has stopped being shown
missile_halo_effect.assign(0);
}
//TODO: fix this
SDL_Delay(20);
#if 0
const int wait_time = ticks + time_resolution - SDL_GetTicks();
if(wait_time > 0 && !hide) {
SDL_Delay(wait_time);
} else if(wait_time < 0) {
//if we're not keeping up, then skip frames
i += minimum<int>(time_resolution*4,-wait_time);
}
#endif
// ticks = SDL_GetTicks();
attack_anim.update_current_frame();
missile_anim.update_current_frame();
def->second.update_frame();
animation_time = attack_anim.get_animation_time();
events::pump();
disp.update_display();
events::pump();
if(!disp.turbo()) SDL_Delay(10);
animation_time = defender.get_animation()->get_animation_time();
}
unit_halo_effect.assign(0);
missile_halo_effect.assign(0);
if(damage > 0 && shown_label == false) {
shown_label = true;
if (update_display){
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
}
sound::play_sound(def->second.type().get_hit_sound());
if(damage > 0 && !hide) {
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
}
if(damage > 0 && def->second.gets_hit(damage)) {
if(def->second.gets_hit(damage)) {
dead = true;
damage = 0;
}
if(leader_loc.valid()){
leader->second.set_standing();
}
disp.invalidate(a);
disp.invalidate(b);
def->second.set_standing();
if(leader_loc.valid() && update_display){
disp.draw_tile(leader_loc.x,leader_loc.y);
}
if(dead) {
unit_die(disp,def->first,def->second,&attack);
unit_display::unit_die(disp,map,def->first,def->second,&attack);
} else {
def->second.set_standing(disp.turbo()?5:1);
}
if(leader_loc.valid()) leader->second.set_standing(disp.turbo()?5:1);
att->second.set_standing(disp.turbo()?5:1);
disp.update_display();
events::pump();
return dead;
}
} //end anon namespace
@ -625,33 +335,33 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
const unit_map::iterator att = units.find(a);
wassert(att != units.end());
unit& attacker = att->second;
const unit_map::iterator def = units.find(b);
wassert(def != units.end());
unit& defender = def->second;
if(b.x > a.x) {
att->second.set_facing_left(true);
def->second.set_facing_left(false);
} else if(b.x < a.x) {
att->second.set_facing_left(false);
def->second.set_facing_left(true);
}
att->second.set_facing(a.get_relative_dir(b));
def->second.set_facing(b.get_relative_dir(a));
if(attack.range_type() == attack_type::LONG_RANGE) {
return unit_attack_ranged(disp, units, a, b, damage, attack, update_display);
return unit_attack_ranged(disp, map,units, a, b, damage, attack, update_display);
}
const bool hits = damage > 0;
unit_animation attack_anim = *attack.animation(hits,get_adjacent_direction(a,b)).first;
const std::string& hit_sound = def->second.type().get_hit_sound();
bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
const int play_hit_sound_at = 0;
const int time_resolution = 20;
const int acceleration = disp.turbo() ? 5 : 1;
int start_time = 500;
int end_time = 0;
attacker.set_attacking(acceleration,hits,attack);
start_time=minimum<int>(start_time,attacker.get_animation()->get_first_frame_time());
end_time=maximum<int>(end_time,attacker.get_animation()->get_last_frame_time());
defender.set_defending(damage,attack.range(),acceleration);
start_time=minimum<int>(start_time,defender.get_animation()->get_first_frame_time());
end_time=maximum<int>(end_time,defender.get_animation()->get_last_frame_time());
const gamemap::location leader_loc = under_leadership(units,a);
unit_map::iterator leader = units.end();
@ -659,213 +369,71 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
LOG_DP << "found leader at " << leader_loc << '\n';
leader = units.find(leader_loc);
wassert(leader != units.end());
leader->second.set_leading();
leader->second.set_leading(disp.turbo()?5:1);
start_time=minimum<int>(start_time,leader->second.get_animation()->get_first_frame_time());
end_time=maximum<int>(end_time,leader->second.get_animation()->get_last_frame_time());
}
const int begin_at = minimum<int>(-200,attack_anim.get_first_frame_time());
// more damage shown for longer, but 1s at most for this factor
const int end_at = maximum<int>(minimum<int>((damage+1)*time_resolution,1000),
maximum<int>(200,attack_anim.get_last_frame_time()));
const double xsrc = disp.get_location_x(a);
const double ysrc = disp.get_location_y(a);
const double xdst = disp.get_location_x(b)*0.6 + xsrc*0.4;
const double ydst = disp.get_location_y(b)*0.6 + ysrc*0.4;
gamemap::location update_tiles[6];
get_adjacent_tiles(b,update_tiles);
bool dead = false;
const int drain_speed = 1*acceleration;
int flash_num = 0;
int ticks = SDL_GetTicks();
if (update_display){
disp.hide_unit(a);
}
const gamemap::TERRAIN src_terrain = map.get_terrain(a);
const gamemap::TERRAIN dst_terrain = map.get_terrain(b);
const double src_height_adjust = attacker.is_flying() ? 0 : map.get_terrain_info(src_terrain).unit_height_adjust() * disp.zoom();
const double dst_height_adjust = attacker.is_flying() ? 0 : map.get_terrain_info(dst_terrain).unit_height_adjust() * disp.zoom();
const double src_submerge = attacker.is_flying() ? 0 : map.get_terrain_info(src_terrain).unit_submerge();
const double dst_submerge = attacker.is_flying() ? 0 : map.get_terrain_info(dst_terrain).unit_submerge();
bool shown_label = false;
util::scoped_resource<int,halo::remover> halo_effect(0);
const std::string* halo_image = NULL;
int halo_x = -1, halo_y = -1;
attack_anim.start_animation(begin_at+1,1, acceleration);
int animation_time = attack_anim.get_animation_time();
def->second.set_defending(hits, attack.range(), animation_time, acceleration);
while(animation_time < end_at && !hide) {
const unit_frame& unit_frame = attack_anim.get_current_frame();
if(!unit_frame.sound.empty()) {
}
if(attack_anim.frame_changed() && !unit_frame.sound.empty()) {
sound::play_sound(unit_frame.sound);
}
if(!hide && hits && !played_hit_sound && animation_time >= play_hit_sound_at) {
sound::play_sound(hit_sound);
played_hit_sound = true;
}
for(int j = 0; j != 6; ++j) {
disp.draw_tile(update_tiles[j].x,update_tiles[j].y);
}
Uint32 defender_colour = 0;
fixed_t defender_alpha = ftofxp(1.0);
if(damage > 0 && animation_time >= 0 && shown_label == false) {
shown_label = true;
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
}
if(damage > 0 && animation_time >= 0) {
if(def->second.gets_hit(minimum<int>(drain_speed,damage))) {
dead = true;
damage = 0;
} else {
damage -= drain_speed;
}
if(flash_num == 0 || flash_num == 2) {
defender_alpha = ftofxp(0.0);
defender_colour = disp.rgb(200,0,0);
}
++flash_num;
}
disp.draw_tile(b.x,b.y,NULL,defender_alpha,defender_colour);
if(leader_loc.valid()) {
disp.draw_tile(leader_loc.x,leader_loc.y);
}
int xoffset = 0;
int new_halo_x = unit_frame.halo_x;
int new_halo_y = unit_frame.halo_y;
const std::string& unit_image_name = unit_frame.image ;
image::locator unit_image;
if(!unit_image_name.empty()) {
unit_image = image::locator(unit_image_name,attacker.team_rgb_range(),attacker.type().flag_rgb());
} else {
unit_image = attacker.image_loc();
}
if(!attacker.facing_left()) {
xoffset *= -1;
new_halo_x *= -1;
}
new_halo_x = int(new_halo_x*disp.zoom());
attacker.restart_animation(start_time,acceleration);
defender.restart_animation(start_time,acceleration);
if(leader_loc.valid()) leader->second.restart_animation(start_time,acceleration);
xoffset = int(double(xoffset)*disp.zoom());
surface image(image::get_image(unit_image));
if(attacker.facing_left() == false) {
image.assign(image::reverse_image(image));
}
const double pos = double(animation_time)/double(animation_time < 0 ? begin_at : end_at);
const int posx = int(pos*xsrc + (1.0-pos)*xdst) + xoffset;
const int posy = int(pos*ysrc + (1.0-pos)*ydst);
const int halo_xpos = posx+disp.hex_size()/2;
const int halo_ypos = posy+disp.hex_size()/2;
if(&unit_frame.halo != halo_image ||
new_halo_x != halo_x ||
new_halo_y != halo_y) {
halo_image = &unit_frame.halo;
halo_x = new_halo_x;
halo_y = new_halo_y;
if(!unit_frame.halo.empty() &&
(!disp.fogged(b.x,b.y) || !disp.fogged(a.x,a.y))) {
halo_effect.assign(halo::add(halo_xpos,halo_ypos,*halo_image));
} else {
halo_effect.assign(0);
}
}
else if(halo_effect != 0) {
halo::set_location(halo_effect,halo_xpos,halo_ypos);
}
const int height_adjust = int(src_height_adjust*pos + dst_height_adjust*(1.0-pos));
const double submerge = src_submerge*pos + dst_submerge*(1.0-pos);
if(image != NULL && !hide) {
disp.draw_unit(posx, posy - height_adjust, image, false, ftofxp(1.0), 0, 0.0, submerge);
}
const int wait_time = ticks + time_resolution - SDL_GetTicks();
if(wait_time > 0 && !hide) {
SDL_Delay(wait_time);
}
ticks = SDL_GetTicks();
attack_anim.update_current_frame();
def->second.update_frame();
animation_time = attack_anim.get_animation_time();
events::pump();
int animation_time = start_time;
while(animation_time < 0 && !hide) {
const double pos = animation_time < attacker.get_animation()->get_first_frame_time()?0.0:
(1.0 - double(animation_time)/double(attacker.get_animation()->get_first_frame_time()));
disp.draw_tile(a.x,a.y,pos*0.6);
//defender.refresh_unit(disp,disp.get_location_x(b), disp.get_location_y(b));
//if(leader_loc.valid()) leader->second.refresh_unit(disp,leader_loc.x,leader_loc.y);
disp.update_display();
events::pump();
if(!disp.turbo()) SDL_Delay(10);
animation_time = attacker.get_animation()->get_animation_time();
}
halo_effect.assign(0);
if(damage > 0 && shown_label == false) {
shown_label = true;
if (update_display){
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
}
sound::play_sound(def->second.type().get_hit_sound());
if(damage > 0 && !hide) {
disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
}
if (update_display){
disp.hide_unit(gamemap::location());
}
if(damage > 0 && def->second.gets_hit(damage)) {
if(def->second.gets_hit(damage)) {
dead = true;
damage = 0;
}
while(!attacker.get_animation()->animation_finished() ||
!defender.get_animation()->animation_finished() ||
(leader_loc.valid() && !leader->second.get_animation()->animation_finished() )) {
const double pos = (1.0-double(animation_time)/double(end_time));
disp.draw_tile(a.x,a.y,pos*0.6);
//defender.refresh_unit(disp,disp.get_location_x(b), disp.get_location_y(b));
//if(leader_loc.valid()) leader->second.refresh_unit(disp,leader_loc.x,leader_loc.y);
disp.update_display();
events::pump();
if(!disp.turbo()) SDL_Delay(10);
animation_time = attacker.get_animation()->get_animation_time();
}
if(leader_loc.valid()){
leader->second.set_standing();
}
disp.invalidate(a);
disp.invalidate(b);
if (update_display){
if(leader_loc.valid()) {
disp.draw_tile(leader_loc.x,leader_loc.y);
}
}
def->second.set_standing();
if(dead) {
unit_display::unit_die(disp,def->first,def->second,&attack);
unit_display::unit_die(disp,map,def->first,def->second,&attack);
} else {
def->second.set_standing(disp.turbo()?5:1);
}
if(leader_loc.valid()) leader->second.set_standing(disp.turbo()?5:1);
att->second.set_standing(disp.turbo()?5:1);
disp.update_display();
events::pump();
return dead;
}
}
} // end unit display namespace

View file

@ -30,7 +30,7 @@ void move_unit(display& disp, const gamemap& map, const std::vector<gamemap::loc
///a function to show a unit fading out. Note that this only shows the effect, it doesn't
///actually kill the unit.
void unit_die(display& disp, const gamemap::location& loc, const unit& u, const attack_type* attack=NULL);
void unit_die(display& disp, const gamemap &map, const gamemap::location& loc, unit& u, const attack_type* attack=NULL);
///a function to make the unit on tile 'a' attack the unit on tile 'b'.
///the 'damage' will be subtracted from the unit's hitpoints, and a die effect will be

View file

@ -145,25 +145,26 @@ bool attack_type::slow() const
return slow_;
}
const std::pair<const unit_animation*,const unit_animation*> attack_type::animation(bool hit,const gamemap::location::DIRECTION dir) const
const attack_type::attack_animation& attack_type::animation(bool hit,const gamemap::location::DIRECTION dir) const
{
//select one of the matching animations at random
std::vector<std::pair<const unit_animation*,const unit_animation*> > options;
std::vector<const attack_animation*> options;
int max_val = -1;
for(std::vector<attack_animation>::const_iterator i = animation_.begin(); i != animation_.end(); ++i) {
int matching = i->matches(hit,dir);
if(matching == max_val) {
options.push_back(std::pair<const unit_animation*,const unit_animation*>(&i->animation,&i->missile_animation));
options.push_back(&*i);
} else if(matching > max_val) {
max_val = matching;
options.erase(options.begin(),options.end());
options.push_back(std::pair<const unit_animation*,const unit_animation*>(&i->animation,&i->missile_animation));
options.push_back(&*i);
}
}
assert(!options.empty());
return options[rand()%options.size()];
return *options[rand()%options.size()];
}
attack_type::attack_animation::attack_animation(const config& cfg):animation(cfg),missile_animation(cfg,"missile_frame"),hits(HIT_OR_MISS)
{
const std::vector<std::string>& my_directions = utils::split(cfg["direction"]);

View file

@ -52,10 +52,8 @@ public:
//this function returns a random animation out of the possible
//animations for this attack. It will not return the same attack
//each time.
const std::pair<const unit_animation*,const unit_animation*> animation(bool hit,gamemap::location::DIRECTION dir=gamemap::location::NDIRECTIONS) const;
bool matches_filter(const config& cfg) const;
bool apply_modification(const config& cfg,std::string* description);
private:
struct attack_animation
{
typedef enum { HIT, MISS, HIT_OR_MISS } hit_type;
@ -70,6 +68,8 @@ private:
hit_type hits;
};
const attack_animation& animation(bool hit,gamemap::location::DIRECTION dir=gamemap::location::NDIRECTIONS) const;
private:
std::vector<attack_animation> animation_;
t_string description_;
std::string id_;