the long promissed new animation engine... report all glitches to me (boucman)
This commit is contained in:
parent
3a7c85d63b
commit
4c14bd8a32
25 changed files with 880 additions and 1210 deletions
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
136
src/actions.cpp
136
src/actions.cpp
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
249
src/display.cpp
249
src/display.cpp
|
@ -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){
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()))
|
||||
|
|
21
src/map.cpp
21
src/map.cpp
|
@ -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"];
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: {
|
||||
|
|
551
src/unit.cpp
551
src/unit.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
50
src/unit.hpp
50
src/unit.hpp
|
@ -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_;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"]);
|
||||
|
|
|
@ -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_;
|
||||
|
|
Loading…
Add table
Reference in a new issue