From e111e5d439b28e581347b88b9e6f07160e2414dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Rosen?= Date: Sat, 12 May 2007 10:33:21 +0000 Subject: [PATCH] unit drawing logic cleanup, should fix various acceleration bugs and restore status bars during fight --- src/actions.cpp | 190 +++++++------------- src/actions.hpp | 4 +- src/ai.cpp | 4 +- src/display.cpp | 37 ++-- src/display.hpp | 2 - src/game_events.cpp | 25 +-- src/menu_events.cpp | 4 +- src/play_controller.cpp | 6 + src/play_controller.hpp | 3 + src/replay.cpp | 4 +- src/unit.cpp | 11 +- src/unit_display.cpp | 371 +++++++++++++++++++++++++++------------- src/unit_display.hpp | 16 +- src/unit_types.cpp | 2 +- 14 files changed, 360 insertions(+), 319 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index 831a42255a5..1056f942981 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -92,7 +92,7 @@ bool can_recruit_on(const gamemap& map, const gamemap::location& leader, const g std::string recruit_unit(const gamemap& map, int side, unit_map& units, unit new_unit, - gamemap::location& recruit_location, display* disp, bool need_castle, bool full_movement) + gamemap::location& recruit_location, bool show, bool need_castle, bool full_movement) { const events::command_disabler disable_commands; @@ -145,32 +145,12 @@ std::string recruit_unit(const gamemap& map, int side, } new_unit.heal_all(); - const bool show = disp != NULL && !disp->turbo() && - !disp->fogged(recruit_location.x,recruit_location.y); - if(show) { - disp->draw(true,true); - } units.add(new std::pair(recruit_location,new_unit)); LOG_NG << "firing prerecruit event\n"; game_events::fire("prerecruit",recruit_location); - if(show) { - unit_map::iterator un = disp->get_units().find(recruit_location); - if( un !=disp->get_units().end()) { - un->second.set_hidden(true); - disp->scroll_to_tile(recruit_location.x,recruit_location.y,display::ONSCREEN); - un->second.set_hidden(false); - un->second.set_recruited(*disp,recruit_location); - while(!un->second.get_animation()->animation_finished()) { - disp->invalidate(recruit_location); - disp->draw(); - events::pump(); - disp->delay(10); - } - un->second.set_standing(*disp,recruit_location); - } - } + if(show)unit_display::unit_recruited(recruit_location); LOG_NG << "firing recruit event\n"; game_events::fire("recruit",recruit_location); @@ -861,14 +841,34 @@ attack::attack(display& gui, const gamemap& map, } } - unit_display::unit_attack(gui_,units_,attacker_,defender_, - damage_defender_takes, - *a_stats_->weapon,d_stats_->weapon, - update_display_,abs_n_attack_); + if(update_display_) { + std::string float_text = ""; + if(hits) { + if (a_stats_->poisons && + !utils::string_bool(d_->second.get_state("poisoned"))) { + float_text = float_text + _("poisoned") + "\n"; + } + + if(a_stats_->slows && !utils::string_bool(d_->second.get_state("slowed"))) { + float_text = float_text + _("slowed") + "\n"; + } + + //if the defender is turned to stone, the fight stops immediately + static const std::string stone_string("stone"); + if (a_stats_->stones) { + float_text = float_text + _("stone") + "\n"; + } + } + + unit_display::unit_attack(attacker_,defender_, + damage_defender_takes, + *a_stats_->weapon,d_stats_->weapon, + abs_n_attack_,float_text); + } bool dies = d_->second.take_hit(damage_defender_takes); LOG_NG << "defender took " << damage_defender_takes << (dies ? " and died" : "") << "\n"; if(dies) { - unit_display::unit_die(gui_,defender_,d_->second,a_stats_->weapon,d_stats_->weapon, &(a_->second)); + unit_display::unit_die(defender_,d_->second,a_stats_->weapon,d_stats_->weapon, &(a_->second)); } attack_stats.attack_result(hits ? (dies ? statistics::attack_context::KILLS : statistics::attack_context::HITS) : statistics::attack_context::MISSES, attacker_damage_); @@ -989,17 +989,11 @@ attack::attack(display& gui, const gamemap& map, } else if(hits) { if (a_stats_->poisons && !utils::string_bool(d_->second.get_state("poisoned"))) { - if (update_display_){ - gui_.float_label(d_->first,_("poisoned"),255,0,0); - } d_->second.set_state("poisoned","yes"); LOG_NG << "defender poisoned\n"; } if(a_stats_->slows && !utils::string_bool(d_->second.get_state("slowed"))) { - if (update_display_){ - gui_.float_label(d_->first,_("slowed"),255,0,0); - } d_->second.set_state("slowed","yes"); defender_damage_ = d_stats_->slow_damage; LOG_NG << "defender slowed\n"; @@ -1008,9 +1002,6 @@ attack::attack(display& gui, const gamemap& map, //if the defender is turned to stone, the fight stops immediately static const std::string stone_string("stone"); if (a_stats_->stones) { - if (update_display_){ - gui_.float_label(d_->first,_("stone"),255,0,0); - } d_->second.set_state("stoned","yes"); n_defends_ = 0; n_attacks_ = 0; @@ -1076,14 +1067,33 @@ attack::attack(display& gui, const gamemap& map, } } - unit_display::unit_attack(gui_,units_,defender_,attacker_, - damage_attacker_takes, - *d_stats_->weapon,a_stats_->weapon, - update_display_,abs_n_defend_); + if(update_display_) { + std::string float_text = ""; + if(hits) { + if (a_stats_->poisons && + !utils::string_bool(d_->second.get_state("poisoned"))) { + float_text = float_text + _("poisoned") + "\n"; + } + + if(a_stats_->slows && !utils::string_bool(d_->second.get_state("slowed"))) { + float_text = float_text + _("slowed") + "\n"; + } + + //if the defender is turned to stone, the fight stops immediately + static const std::string stone_string("stone"); + if (a_stats_->stones) { + float_text = float_text + _("stone") + "\n"; + } + } + unit_display::unit_attack(defender_,attacker_, + damage_attacker_takes, + *d_stats_->weapon,a_stats_->weapon, + abs_n_defend_,float_text); + } bool dies = a_->second.take_hit(damage_attacker_takes); LOG_NG << "attacker took " << damage_attacker_takes << (dies ? " and died" : "") << "\n"; if(dies) { - unit_display::unit_die(gui_,attacker_,a_->second,a_stats_->weapon,d_stats_->weapon, &(d_->second)); + unit_display::unit_die(attacker_,a_->second,a_stats_->weapon,d_stats_->weapon, &(d_->second)); } if(ran_results == NULL) { config cfg; @@ -1196,17 +1206,11 @@ attack::attack(display& gui, const gamemap& map, } else if(hits) { if (d_stats_->poisons && !utils::string_bool(a_->second.get_state("poisoned"))) { - if (update_display_){ - gui_.float_label(a_->first,_("poisoned"),255,0,0); - } a_->second.set_state("poisoned","yes"); LOG_NG << "attacker poisoned\n"; } if(d_stats_->slows && !utils::string_bool(a_->second.get_state("slowed"))) { - if (update_display_){ - gui_.float_label(a_->first,_("slowed"),255,0,0); - } a_->second.set_state("slowed","yes"); attacker_damage_ = a_stats_->slow_damage; LOG_NG << "attacker slowed\n"; @@ -1216,9 +1220,6 @@ attack::attack(display& gui, const gamemap& map, //if the attacker is turned to stone, the fight stops immediately static const std::string stone_string("stone"); if (d_stats_->stones) { - if (update_display_){ - gui_.float_label(a_->first,_("stone"),255,0,0); - } a_->second.set_state("stoned","yes"); n_defends_ = 0; n_attacks_ = 0; @@ -1477,80 +1478,17 @@ void calculate_healing(display& disp, const gamemap& map, } else if(healing < neg_max) { healing = neg_max; } - if(healing == 0) { - continue; - } - if (disp.turbo() || recorder.is_skipping() - || disp.fogged(i->first.x, i->first.y) - || !update_display - || (i->second.invisible(i->first,units,teams) && + if ( !recorder.is_skipping() + && update_display + && !(i->second.invisible(i->first,units,teams) && teams[disp.viewing_team()].is_enemy(side))) { - // Simple path. - if (healing > 0) - i->second.heal(healing); - else if (healing < 0) - i->second.take_hit(-healing); - continue; - } - - if (update_display){ - // This is all the pretty stuff. - int start_time = INT_MAX; - disp.scroll_to_tile(i->first.x, i->first.y, display::ONSCREEN); - disp.select_hex(i->first); - - for(std::vector::iterator heal_anim_it = healers.begin(); heal_anim_it != healers.end(); ++heal_anim_it) { - (*heal_anim_it)->second.set_facing((*heal_anim_it)->first.get_relative_dir(i->first)); - (*heal_anim_it)->second.set_healing(disp,(*heal_anim_it)->first,healing); - start_time = (*heal_anim_it)->second.get_animation()->get_begin_time(); - } - if (healing < 0) { - i->second.set_poisoned(disp,i->first, -healing); - start_time = minimum(start_time, i->second.get_animation()->get_begin_time()); - // FIXME - sound::play_sound("poison.ogg"); - disp.float_label(i->first, lexical_cast(-healing), 255,0,0); - } else { - i->second.set_healed(disp,i->first, healing); - start_time = minimum(start_time, i->second.get_animation()->get_begin_time()); - sound::play_sound("heal.wav"); - disp.float_label(i->first, lexical_cast(healing), 0,255,0); - } - // restart all anims in a synchronized way - i->second.restart_animation(disp, start_time); - for(std::vector::iterator heal_reanim_it = healers.begin(); heal_reanim_it != healers.end(); ++heal_reanim_it) { - (*heal_reanim_it)->second.restart_animation(disp, start_time); - } - - bool finished; - do { - finished = (i->second.get_animation()->animation_finished()); - disp.invalidate(i->first); - for(std::vector::iterator heal_fanim_it = healers.begin(); heal_fanim_it != healers.end(); ++heal_fanim_it) { - finished &= (*heal_fanim_it)->second.get_animation()->animation_finished(); - disp.invalidate((*heal_fanim_it)->first); - } - if (healing > 0) { - i->second.heal(1); - --healing; - } else if (healing < 0) { - i->second.take_hit(1); - ++healing; - } - finished &= (!healing); - disp.draw(); - events::pump(); - disp.delay(10); - } while (!finished); - - i->second.set_standing(disp,i->first); - for(std::vector::iterator heal_sanim_it = healers.begin(); heal_sanim_it != healers.end(); ++heal_sanim_it) { - (*heal_sanim_it)->second.set_standing(disp,(*heal_sanim_it)->first); - } - disp.update_display(); - events::pump(); + unit_display::unit_healing(i->second,i->first,healers,healing); } + if (healing > 0) + i->second.heal(healing); + else if (healing < 0) + i->second.take_hit(-healing); } } @@ -1988,9 +1926,7 @@ size_t move_unit(display* disp, const game_data& gamedata, //move the unit on the screen. Hide the unit in its current location, but don't actually //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) { - unit_display::move_unit(*disp,map,steps,ui->second,units,teams); - } + unit_display::move_unit(map,steps,ui->second,teams); ui->second.set_movement(moves_left); @@ -1998,12 +1934,6 @@ size_t move_unit(display* disp, const game_data& gamedata, p->first = steps.back(); units.add(p); ui = units.find(p->first); - ui->second.set_standing(*disp,ui->first); - if(disp != NULL) { - disp->invalidate_unit(); - disp->invalidate(steps.back()); - disp->draw(); - } if(move_recorder != NULL) { move_recorder->add_movement(steps.front(),steps.back()); diff --git a/src/actions.hpp b/src/actions.hpp index 10b267f37a2..a4fe02f72d6 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -50,8 +50,8 @@ bool can_recruit_on(const gamemap& map, const gamemap::location& leader, const g //If the unit cannot be recruited, then a human-readable message //describing why not will be returned. On success, the return string is empty std::string recruit_unit(const gamemap& map, int team, unit_map& units, - unit u, gamemap::location& recruit_location, - display *disp=NULL, bool need_castle=true, bool full_movement=false); + unit u, gamemap::location& recruit_location,bool show=false, + bool need_castle=true, bool full_movement=false); /* The battle_context class computes the statistics of a battle between an * attacker and a defender unit. diff --git a/src/ai.cpp b/src/ai.cpp index 8938d3981ef..7c22804f40a 100644 --- a/src/ai.cpp +++ b/src/ai.cpp @@ -482,13 +482,13 @@ gamemap::location ai_interface::move_unit_partial(location from, location to, steps.push_back(to); //add the destination to the steps - if(show_move && unit_display::unit_visible_on_path(info_.disp,steps, + if(show_move && unit_display::unit_visible_on_path(steps, u_it->second, info_.units,info_.teams)) { info_.disp.scroll_to_tiles(from.x,from.y,to.x,to.y); unit_map::iterator up = info_.units.find(u_it->first); - unit_display::move_unit(info_.disp,info_.map,steps,up->second,info_.units,info_.teams); + unit_display::move_unit(info_.map,steps,up->second,info_.teams); } } } diff --git a/src/display.cpp b/src/display.cpp index f7abcf51f22..72e2e79c9a1 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -168,7 +168,7 @@ void display::new_turn() { const time_of_day& tod = status_.get_time_of_day(); - if(!turbo() && !first_turn_) { + if( !first_turn_) { image::set_image_mask(""); const time_of_day& old_tod = status_.get_previous_time_of_day(); @@ -177,8 +177,8 @@ void display::new_turn() const surface old_mask(image::get_image(old_tod.image_mask,image::UNMASKED)); const surface new_mask(image::get_image(tod.image_mask,image::UNMASKED)); - const int niterations = 10; - const int frame_time = 30; + const int niterations = (int)(10/turbo_speed()); + const int frame_time = (int)(30/turbo_speed()); const int starting_ticks = SDL_GetTicks(); for(int i = 0; i != niterations; ++i) { @@ -582,7 +582,7 @@ void display::scroll_to_tile(int x, int y, SCROLL_TYPE scroll_type, bool check_f int xmove = xpos - xpos_; int ymove = ypos - ypos_; - if(scroll_type == WARP || turbo()) { + if(scroll_type == WARP ) { scroll(xmove,ymove); draw(); return; @@ -599,8 +599,8 @@ void display::scroll_to_tile(int x, int y, SCROLL_TYPE scroll_type, bool check_f int t_prev = SDL_GetTicks(); // those values might need some fine-tuning: - const double accel_time = 0.3; // seconds - const double decel_time = 0.4; // seconds + const double accel_time = 0.3*turbo_speed(); // seconds + const double decel_time = 0.4*turbo_speed(); // seconds double velocity = 0.0; while (dist_moved < dist_total) { @@ -617,7 +617,7 @@ void display::scroll_to_tile(int x, int y, SCROLL_TYPE scroll_type, bool check_f //std::cout << t << " " << hypot(x_old, y_old) << "\n"; double velocity_max = preferences::scroll_speed() * 80.0; - if (turbo()) velocity_max *= 4.0; + velocity_max *= turbo_speed(); double accel = velocity_max / accel_time; double decel = velocity_max / decel_time; @@ -2345,19 +2345,15 @@ void display::set_playing_team(size_t team) } -bool display::turbo() const +double display::turbo_speed() const { bool res = turbo_; if(keys_[SDLK_LSHIFT] || keys_[SDLK_RSHIFT]) { res = !res; } - return res || screen_.faked(); -} - -double display::turbo_speed() const -{ - if (turbo()) + res |= screen_.faked(); + if (res) return turbo_speed_; else return 1.0; @@ -2365,23 +2361,10 @@ double display::turbo_speed() const void display::set_turbo_speed(const double speed) { -#if 0 - // speed < 2 don't make sense - if (speed < 2) - return; - if (speed > 20) - turbo_speed_ = 20; - else -#endif turbo_speed_ = speed; } //Delay routines: use these not SDL_Delay (for --nogui). -void display::non_turbo_delay() const -{ - if (!turbo()) - delay(10); -} void display::delay(unsigned int milliseconds) const { diff --git a/src/display.hpp b/src/display.hpp index 87c669c3feb..e8c2a40f1a6 100644 --- a/src/display.hpp +++ b/src/display.hpp @@ -325,14 +325,12 @@ public: //functions to set/get whether 'turbo' mode is on. When turbo mode is on, //everything moves much faster. - bool turbo() const; void set_turbo(const bool turbo) { turbo_ = turbo; } double turbo_speed() const; void set_turbo_speed(const double speed); //Delay routines: use these not SDL_Delay (for --nogui). - void non_turbo_delay() const; void delay(unsigned int milliseconds) const; //function which determines whether a grid should be overlayed on the diff --git a/src/game_events.cpp b/src/game_events.cpp index e8d8378a99b..838f4c74f81 100644 --- a/src/game_events.cpp +++ b/src/game_events.cpp @@ -810,8 +810,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, game_map->x(), game_map->y()); wassert(route.steps.size() > 0); } - unit_display::move_unit(*screen, *game_map, route.steps, dummy_unit, - *units, *teams); + unit_display::move_unit( *game_map, route.steps, dummy_unit, *teams); src = dst; } @@ -1349,11 +1348,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, if(game_map->on_board(loc)) { loc = find_vacant_tile(*game_map,*units,loc); const bool show = screen != NULL && !screen->fogged(loc.x,loc.y); - const bool animate = show && !screen->turbo() && cfg["animate"] != ""; - - if (show) { - screen->draw(true,true); - } + const bool animate = show && cfg["animate"] != ""; units->erase(loc); units->add(new std::pair(loc,new_unit)); @@ -1366,17 +1361,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, unit_map::iterator un = units->find(loc); if(animate) { - un->second.set_hidden(true); - screen->scroll_to_tile(loc.x,loc.y,display::ONSCREEN); - un->second.set_hidden(false); - un->second.set_recruited(*screen,un->first); - while(!un->second.get_animation()->animation_finished()) { - screen->invalidate(loc); - screen->draw(); - events::pump(); - screen->delay(10); - } - un->second.set_standing(*screen, un->first); + unit_display::unit_recruited(loc); } else if(show) un->second.redraw_unit(*screen, loc); @@ -1423,7 +1408,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, gamemap::location loc = cfg_to_loc(cfg); unit to_recruit(*u); avail.erase(u); //erase before recruiting, since recruiting can fire more events - recruit_unit(*game_map,index+1,*units,to_recruit,loc,utils::string_bool(cfg["show"],true) ? NULL : screen,false,true); + recruit_unit(*game_map,index+1,*units,to_recruit,loc,utils::string_bool(cfg["show"],true),false,true); unit_recalled = true; break; } @@ -1696,7 +1681,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, if(game_events::unit_matches_filter(un,cfg)) { if(utils::string_bool(cfg["animate"])) { screen->scroll_to_tile(un->first.x,un->first.y); - unit_display::unit_die(*screen,un->first,un->second); + unit_display::unit_die(un->first,un->second); } if(utils::string_bool(cfg["fire_event"])) { diff --git a/src/menu_events.cpp b/src/menu_events.cpp index 3f45ee4e7ae..5479ab62973 100644 --- a/src/menu_events.cpp +++ b/src/menu_events.cpp @@ -990,7 +990,7 @@ namespace events{ action.starting_moves = u->second.movement_left(); - unit_display::move_unit(*gui_,map_,route,u->second,units_,teams_); + unit_display::move_unit(map_,route,u->second,teams_); std::pair *up = units_.extract(u->first); up->second.set_goto(gamemap::location()); up->second.set_movement(starting_moves); @@ -1112,7 +1112,7 @@ namespace events{ action.starting_moves = u->second.movement_left(); - unit_display::move_unit(*gui_,map_,route,u->second,units_,teams_); + unit_display::move_unit(map_,route,u->second,teams_); std::pair *up = units_.extract(u->first); up->second.set_goto(gamemap::location()); up->second.set_movement(starting_moves); diff --git a/src/play_controller.cpp b/src/play_controller.cpp index 1056f644a7c..59906f786e9 100644 --- a/src/play_controller.cpp +++ b/src/play_controller.cpp @@ -21,6 +21,7 @@ #include "replay.hpp" #include "sound.hpp" #include "variable.hpp" +#include "wassert.hpp" #define LOG_NG LOG_STREAM(info, engine) @@ -43,6 +44,8 @@ play_controller::play_controller(const config& level, const game_data& gameinfo, game_config::add_color_info(level); init(video); + wassert(singleton_==NULL); + singleton_=this; } play_controller::~play_controller(){ @@ -52,6 +55,7 @@ play_controller::~play_controller(){ delete events_manager_; delete soundsources_manager_; delete gui_; + singleton_=NULL; } void play_controller::init(CVideo& video){ @@ -891,3 +895,5 @@ hotkey::ACTION_STATE play_controller::get_action_state(hotkey::HOTKEY_COMMAND co return hotkey::ACTION_STATELESS; } } + +play_controller* play_controller::singleton_ = NULL; diff --git a/src/play_controller.hpp b/src/play_controller.hpp index 60070f3110a..12dafc34e39 100644 --- a/src/play_controller.hpp +++ b/src/play_controller.hpp @@ -74,6 +74,8 @@ public: virtual void play_side(const unsigned int team_num, bool save) = 0; const int get_ticks(); + display * get_display() { return gui_; } + static play_controller * get_singleton() { return singleton_; } protected: void handle_event(const SDL_Event& event); @@ -154,6 +156,7 @@ private: void expand_wml_commands(std::vector& items); std::vector wml_commands_; + static play_controller* singleton_; #define MAX_WML_COMMANDS 7 }; diff --git a/src/replay.cpp b/src/replay.cpp index e17d589e258..aa2f6c8976b 100644 --- a/src/replay.cpp +++ b/src/replay.cpp @@ -888,13 +888,13 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo, rt->second.steps.push_back(dst); - if(!replayer.is_skipping() && unit_display::unit_visible_on_path(disp,rt->second.steps,u->second,units,teams)) { + if(!replayer.is_skipping() && unit_display::unit_visible_on_path(rt->second.steps,u->second,units,teams)) { disp.scroll_to_tiles(src.x,src.y,dst.x,dst.y); } if(!replayer.is_skipping()) { - unit_display::move_unit(disp,map,rt->second.steps,u->second,units,teams); + unit_display::move_unit(map,rt->second.steps,u->second,teams); } else{ //unit location needs to be updated diff --git a/src/unit.cpp b/src/unit.cpp index b7d73ff719e..3e953a8574c 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -1318,7 +1318,7 @@ void unit::read(const config& cfg) healed_animations_.push_back(healed_animation(**healed_anim)); } if(healed_animations_.empty()) { - healed_animations_.push_back(healed_animation(0,unit_frame(absolute_image(),240,"1.0","",display::rgb(255,255,255),"0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30"))); + healed_animations_.push_back(healed_animation(0,unit_frame(absolute_image(),240,"1.0","",display::rgb(255,255,255),"0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30"))); // always have a healed animation } @@ -1508,7 +1508,7 @@ void unit::set_standing(const display &disp,const gamemap::location& loc, bool w void unit::set_defending(const display &disp,const gamemap::location& loc, int damage,const attack_type* attack,const attack_type* secondary_attack,int swing_num) { state_ = STATE_DEFENDING; - draw_bars_ = false; + draw_bars_ = true; delete anim_; @@ -1551,7 +1551,7 @@ void unit::set_extra_anim(const display &disp,const gamemap::location& loc, std: const unit_animation & unit::set_attacking(const display &disp,const gamemap::location& loc,int damage,const attack_type& type,const attack_type* secondary_attack,int swing_num) { state_ = STATE_ATTACKING; - draw_bars_ = false; + draw_bars_ = true; delete anim_; @@ -1609,7 +1609,6 @@ void unit::set_recruited(const display &disp,const gamemap::location& loc) delete anim_; anim_ = new recruit_animation(recruiting_animation(disp,loc)); - // add a fade in effect anim_->start_animation(anim_->get_begin_time(), false, disp.turbo_speed()); frame_begin_time_ = anim_->get_begin_time() -1; } @@ -1651,7 +1650,7 @@ void unit::set_teleporting(const display &disp,const gamemap::location& loc) void unit::set_dying(const display &disp,const gamemap::location& loc,const attack_type* attack,const attack_type* secondary_attack) { state_ = STATE_DYING; - draw_bars_ = false; + draw_bars_ = true; delete anim_; @@ -1675,7 +1674,7 @@ void unit::set_healing(const display &disp,const gamemap::location& loc,int heal void unit::set_victorious(const display &disp,const gamemap::location& loc,const attack_type* attack,const attack_type* secondary_attack) { state_ = STATE_VICTORIOUS; - draw_bars_ = false; + draw_bars_ = true; delete anim_; diff --git a/src/unit_display.cpp b/src/unit_display.cpp index 19dea7b5654..1bb26efb5b4 100644 --- a/src/unit_display.cpp +++ b/src/unit_display.cpp @@ -27,51 +27,54 @@ #include "unit_display.hpp" #include "util.hpp" #include "wassert.hpp" +#include "play_controller.hpp" #define LOG_DP LOG_STREAM(info, display) -static void teleport_unit_between(display& disp, const gamemap::location& a, const gamemap::location& b, unit& temp_unit) +static void teleport_unit_between( const gamemap::location& a, const gamemap::location& b, unit& temp_unit) { - if(disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y)) { + display* disp = play_controller::get_singleton()->get_display(); + if(!disp || disp->update_locked() || disp->fogged(a.x,a.y) && disp->fogged(b.x,b.y)) { return; } - temp_unit.set_teleporting(disp,a); - if (!disp.fogged(a.x, a.y)) { // teleport - disp.scroll_to_tile(a.x,a.y,display::ONSCREEN); + temp_unit.set_teleporting(*disp,a); + if (!disp->fogged(a.x, a.y)) { // teleport + disp->scroll_to_tile(a.x,a.y,display::ONSCREEN); while(!temp_unit.get_animation()->animation_finished() && temp_unit.get_animation()->get_animation_time() < 0) { - disp.invalidate(a); - disp.place_temporary_unit(temp_unit, a); - disp.draw(); + disp->invalidate(a); + disp->place_temporary_unit(temp_unit, a); + disp->draw(); events::pump(); - disp.delay(10); + disp->delay(10); } } - if (!disp.fogged(b.x, b.y)) { // teleport - temp_unit.restart_animation(disp,0); - disp.scroll_to_tile(b.x,b.y,display::ONSCREEN); + if (!disp->fogged(b.x, b.y)) { // teleport + temp_unit.restart_animation(*disp,0); + disp->scroll_to_tile(b.x,b.y,display::ONSCREEN); while(!temp_unit.get_animation()->animation_finished()) { - disp.invalidate(b); - disp.place_temporary_unit(temp_unit, b); - disp.draw(); + disp->invalidate(b); + disp->place_temporary_unit(temp_unit, b); + disp->draw(); events::pump(); - disp.delay(10); + disp->delay(10); } } - temp_unit.set_standing(disp,b); - disp.update_display(); + temp_unit.set_standing(*disp,b); + disp->update_display(); events::pump(); } -static void move_unit_between(display& disp, const gamemap& map, const gamemap::location& a, const gamemap::location& b, unit& temp_unit) +static void move_unit_between( const gamemap& map, const gamemap::location& a, const gamemap::location& b, unit& temp_unit) { - if(disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y)) { + display* disp = play_controller::get_singleton()->get_display(); + if(!disp || disp->update_locked() || disp->fogged(a.x,a.y) && disp->fogged(b.x,b.y)) { return; } const t_translation::t_letter dst_terrain = map.get_terrain(b); - const double acceleration = disp.turbo_speed(); + const double acceleration = disp->turbo_speed(); gamemap::location src_adjacent[6]; get_adjacent_tiles(a, src_adjacent); @@ -79,22 +82,22 @@ static void move_unit_between(display& disp, const gamemap& map, const gamemap:: gamemap::location dst_adjacent[6]; get_adjacent_tiles(b, dst_adjacent); - const int total_mvt_time = (int)150 * temp_unit.movement_cost(dst_terrain)/acceleration; + const int total_mvt_time = 150 * (int)(temp_unit.movement_cost(dst_terrain)/acceleration); const unsigned int start_time = SDL_GetTicks(); int mvt_time = 1; - disp.scroll_to_tiles(a.x,a.y,b.x,b.y,display::ONSCREEN); + disp->scroll_to_tiles(a.x,a.y,b.x,b.y,display::ONSCREEN); while(mvt_time < total_mvt_time-1) { // one draw in each hex at least - disp.delay(10); + disp->delay(10); mvt_time = SDL_GetTicks() -start_time; if(mvt_time >=total_mvt_time) mvt_time = total_mvt_time -1; double pos =double(mvt_time)/total_mvt_time; const gamemap::location& ref_loc =pos<0.5?a:b; if(pos >= 0.5) pos = pos -1; - temp_unit.set_walking(disp,ref_loc); + temp_unit.set_walking(*disp,ref_loc); temp_unit.set_offset(pos); - disp.place_temporary_unit(temp_unit,ref_loc); - disp.draw(); + disp->place_temporary_unit(temp_unit,ref_loc); + disp->draw(); events::pump(); } @@ -103,10 +106,12 @@ static void move_unit_between(display& disp, const gamemap& map, const gamemap:: namespace unit_display { -bool unit_visible_on_path(display& disp, const std::vector& path, const unit& u, const unit_map& units, const std::vector& teams) +bool unit_visible_on_path( const std::vector& path, const unit& u, const unit_map& units, const std::vector& teams) { + display* disp = play_controller::get_singleton()->get_display(); + wassert(disp); for(size_t i = 0; i+1 < path.size(); ++i) { - const bool invisible = teams[u.side()-1].is_enemy(int(disp.viewing_team()+1)) && + const bool invisible = teams[u.side()-1].is_enemy(int(disp->viewing_team()+1)) && u.invisible(path[i],units,teams) && u.invisible(path[i+1],units,teams); if(!invisible) { @@ -117,9 +122,12 @@ bool unit_visible_on_path(display& disp, const std::vector& p return false; } -void move_unit(display& disp, const gamemap& map, const std::vector& path, unit& u, const unit_map& units, const std::vector& teams) +void move_unit( const gamemap& map, const std::vector& path, unit& u, const std::vector& teams) { + display* disp = play_controller::get_singleton()->get_display(); wassert(!path.empty()); + wassert(disp); + const unit_map& units = disp->get_units(); bool previous_visible = false; bool was_hidden = u.get_hidden(); @@ -131,48 +139,49 @@ void move_unit(display& disp, const gamemap& map, const std::vectorremove_footstep(path[i]); - bool invisible = teams[temp_unit.side()-1].is_enemy(int(disp.viewing_team()+1)) && + bool invisible = teams[temp_unit.side()-1].is_enemy(int(disp->viewing_team()+1)) && temp_unit.invisible(path[i],units,teams) && temp_unit.invisible(path[i+1],units,teams); if(!invisible) { if( !tiles_adjacent(path[i], path[i+1])) { - teleport_unit_between(disp,path[i],path[i+1],temp_unit); + teleport_unit_between(path[i],path[i+1],temp_unit); } else { - move_unit_between(disp,map,path[i],path[i+1],temp_unit); + move_unit_between(map,path[i],path[i+1],temp_unit); } previous_visible = true; } else if(previous_visible) { gamemap::location arr[6]; - disp.invalidate(path[i]); + disp->invalidate(path[i]); get_adjacent_tiles(path[i], arr); for (unsigned int i = 0; i < 6; i++) { - disp.invalidate(arr[i]); + disp->invalidate(arr[i]); } - disp.draw(); + disp->draw(); previous_visible = false; } else { previous_visible = false; } } - disp.remove_temporary_unit(); + disp->remove_temporary_unit(); u.set_facing(path[path.size()-2].get_relative_dir(path[path.size()-1])); - u.set_standing(disp,path[path.size()-1]); + u.set_standing(*disp,path[path.size()-1]); //make sure the entire path is cleaned properly for(std::vector::const_iterator it = path.begin(); it != path.end(); ++it) { - disp.invalidate(*it); + disp->invalidate(*it); } u.set_hidden(was_hidden); } -void unit_die(display& disp,const gamemap::location& loc, unit& loser, +void unit_die(const gamemap::location& loc, unit& loser, const attack_type* attack,const attack_type* secondary_attack, unit* winner) { - if(disp.update_locked() || disp.fogged(loc.x,loc.y) || preferences::show_combat() == false) { + display* disp = play_controller::get_singleton()->get_display(); + if(!disp ||disp->update_locked() || disp->fogged(loc.x,loc.y) || preferences::show_combat() == false) { return; } const std::string& die_sound = loser.die_sound(); @@ -180,41 +189,44 @@ const attack_type* attack,const attack_type* secondary_attack, unit* winner) sound::play_sound(die_sound); } - loser.set_dying(disp,loc,attack,secondary_attack); + loser.set_dying(*disp,loc,attack,secondary_attack); if(winner == NULL) { //test to see if there is no victor. while(!loser.get_animation()->animation_finished()) { - disp.invalidate(loc); - disp.draw(); + disp->invalidate(loc); + disp->draw(); events::pump(); - disp.delay(10); + disp->delay(10); } return; } - winner->set_victorious(disp,loc,attack,secondary_attack); + winner->set_victorious(*disp,loc,attack,secondary_attack); int start_time = minimum(loser.get_animation()->get_begin_time(),winner->get_animation()->get_begin_time()); - winner->restart_animation(disp,start_time); - loser.restart_animation(disp,start_time); + winner->restart_animation(*disp,start_time); + loser.restart_animation(*disp,start_time); while((!loser.get_animation()->animation_would_finish()) || ((!winner->get_animation()->animation_would_finish()))) { - disp.invalidate(loc); - disp.draw(); + disp->invalidate(loc); + disp->draw(); events::pump(); - disp.delay(10); + disp->delay(10); } } -static void unit_attack_ranged(display& disp, unit_map& units, +static void unit_attack_ranged( const gamemap::location& a, const gamemap::location& b, - int damage, const attack_type& attack, const attack_type* secondary_attack,bool update_display, int swing) + int damage, const attack_type& attack, const attack_type* secondary_attack, int swing,std::string hit_text) { - const bool hide = disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y) - || preferences::show_combat() == false || (!update_display); + display* disp = play_controller::get_singleton()->get_display(); + if(!disp) return; + const bool hide = disp->update_locked() || disp->fogged(a.x,a.y) && disp->fogged(b.x,b.y) + || preferences::show_combat() == false ; + unit_map& units = disp->get_units(); log_scope("unit_attack_range"); const unit_map::iterator att = units.find(a); @@ -223,16 +235,20 @@ static void unit_attack_ranged(display& disp, unit_map& units, const unit_map::iterator def = units.find(b); wassert(def != units.end()); - unit& defender = def->second; + bool def_was_hidden = def->second.get_hidden(); + def->second.set_hidden(true); + unit defender = def->second; + disp->place_temporary_unit(defender,b); + defender.set_hidden(false); - const double acceleration = disp.turbo_speed(); + const double acceleration = disp->turbo_speed(); // more damage shown for longer, but 1s at most for this factor - const double xsrc = disp.get_location_x(a); - const double ysrc = disp.get_location_y(a) - (attacker.is_flying() ? 0 : disp.get_map().get_terrain_info(disp.get_map().get_terrain(a)).unit_height_adjust()); - const double xdst = disp.get_location_x(b); - const double ydst = disp.get_location_y(b) -( defender.is_flying() ? 0 : disp.get_map().get_terrain_info(disp.get_map().get_terrain(b)).unit_height_adjust()); + const double xsrc = disp->get_location_x(a); + const double ysrc = disp->get_location_y(a) - (attacker.is_flying() ? 0 : disp->get_map().get_terrain_info(disp->get_map().get_terrain(a)).unit_height_adjust()); + const double xdst = disp->get_location_x(b); + const double ydst = disp->get_location_y(b) -( defender.is_flying() ? 0 : disp->get_map().get_terrain_info(disp->get_map().get_terrain(b)).unit_height_adjust()); gamemap::location update_tiles[6]; get_adjacent_tiles(b,update_tiles); @@ -241,7 +257,7 @@ static void unit_attack_ranged(display& disp, unit_map& units, // start leader and attacker animation, wait for attacker animation to end - unit_animation missile_animation = attacker.set_attacking(disp,a,damage,attack,secondary_attack,swing); + unit_animation missile_animation = attacker.set_attacking(*disp,a,damage,attack,secondary_attack,swing); const gamemap::location leader_loc = under_leadership(units,a); unit_map::iterator leader = units.end(); if(leader_loc.valid()){ @@ -249,7 +265,7 @@ static void unit_attack_ranged(display& disp, unit_map& units, leader = units.find(leader_loc); wassert(leader != units.end()); leader->second.set_facing(leader_loc.get_relative_dir(a)); - leader->second.set_leading(disp,leader_loc); + leader->second.set_leading(*disp,leader_loc); } int animation_time; @@ -279,15 +295,15 @@ static void unit_attack_ranged(display& disp, unit_map& units, } const bool vertical_dir = (a.x == b.x) ? true:false; - defender.set_defending(disp,b,damage,&attack,secondary_attack,swing); + defender.set_defending(*disp,b,damage,&attack,secondary_attack,swing); // min of attacker, defender, missile and -200 int start_time = -200; start_time = minimum(start_time,defender.get_animation()->get_begin_time()); start_time = minimum(start_time,missile_animation.get_begin_time()); start_time = minimum(start_time,attacker.get_animation()->get_begin_time()); missile_animation.start_animation(start_time,false,acceleration); - defender.restart_animation(disp,start_time); - attacker.restart_animation(disp,start_time); + defender.restart_animation(*disp,start_time); + attacker.restart_animation(*disp,start_time); animation_time = defender.get_animation()->get_animation_time(); bool sound_played = false ; int missile_frame_halo = halo::NO_HALO; @@ -296,7 +312,8 @@ static void unit_attack_ranged(display& disp, unit_map& units, !attacker.get_animation()->animation_would_finish() || !defender.get_animation()->animation_would_finish() || !missile_animation.animation_finished() || - (leader_loc.valid() && !leader->second.get_animation()->animation_finished())) + (leader_loc.valid() && !leader->second.get_animation()->animation_finished()) || + damage >0) ){ const unit_frame& missile_frame = missile_animation.get_current_frame(); double pos = missile_frame.offset(missile_animation.get_current_frame_time()); @@ -304,21 +321,21 @@ static void unit_attack_ranged(display& disp, unit_map& units, pos = double(animation_time -missile_animation.get_begin_time())/ double(missile_animation.get_end_time()-missile_animation.get_begin_time()); } - disp.invalidate(b); - disp.invalidate(a); - if(leader_loc.valid()) disp.invalidate(leader_loc); + disp->invalidate(b); + disp->invalidate(a); + if(leader_loc.valid()) disp->invalidate(leader_loc); halo::remove(missile_halo); halo::remove(missile_frame_halo); missile_halo = halo::NO_HALO; missile_frame_halo = halo::NO_HALO; if(animation_time > missile_animation.get_begin_time() && animation_time < missile_animation.get_end_time() && - (!disp.fogged(b.x,b.y) || !disp.fogged(a.x,a.y))) { + (!disp->fogged(b.x,b.y) || !disp->fogged(a.x,a.y))) { const int posx = int(pos*xdst + (1.0-pos)*xsrc); const int posy = int(pos*ydst + (1.0-pos)*ysrc); image::locator missile_image= missile_frame.image(); - const int d = disp.hex_size() / 2; + const int d = disp->hex_size() / 2; if(vertical_dir) { missile_image = missile_frame.image(); } else { @@ -346,47 +363,54 @@ static void unit_attack_ranged(display& disp, unit_map& units, orientation); } - if(damage > 0 && animation_time > 0 && !sound_played) { + if(!sound_played && animation_time > 0) { sound_played = true; - sound::play_sound(def->second.get_hit_sound()); - disp.float_label(b,lexical_cast(damage),255,0,0); - disp.invalidate_unit(); + std::string text ; + if(damage) text = lexical_cast(damage); + if(!hit_text.empty()) text = text + "\n" + hit_text; + sound::play_sound(defender.get_hit_sound()); + disp->float_label(b,text,255,0,0); + disp->invalidate_unit(); } - disp.draw(); + if(damage > 0 && animation_time > 0) { + defender.take_hit(1); + damage--; + disp->invalidate_unit(); + } + disp->draw(); events::pump(); missile_animation.update_last_draw_time(); - disp.delay(10); + disp->delay(10); // we use missile animation because it's the only one not reseted in the middle to go to standing animation_time = missile_animation.get_animation_time(); } - // make sure get hit sound is always played and labels always displayed - if(damage > 0 && !hide && !sound_played) { - sound_played = true; - sound::play_sound(def->second.get_hit_sound()); - disp.float_label(b,lexical_cast(damage),255,0,0); - disp.invalidate_unit(); - } + halo::remove(missile_halo); missile_halo = halo::NO_HALO; halo::remove(missile_frame_halo); missile_frame_halo = halo::NO_HALO; - if(leader_loc.valid()) leader->second.set_standing(disp,leader_loc); - att->second.set_standing(disp,a); - def->second.set_standing(disp,b); + if(leader_loc.valid()) leader->second.set_standing(*disp,leader_loc); + att->second.set_standing(*disp,a); + def->second.set_standing(*disp,b); + def->second.set_hidden(def_was_hidden); + disp->remove_temporary_unit(); } -void unit_attack(display& disp, unit_map& units, +void unit_attack( const gamemap::location& a, const gamemap::location& b, int damage, const attack_type& attack, const attack_type* secondary_attack, - bool update_display, int swing) + int swing,std::string hit_text) { - const bool hide = disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y) - || preferences::show_combat() == false || (!update_display); + display* disp = play_controller::get_singleton()->get_display(); + if(!disp) return; + unit_map& units = disp->get_units(); + const bool hide = disp->update_locked() || disp->fogged(a.x,a.y) && disp->fogged(b.x,b.y) + || preferences::show_combat() == false; if(!hide) { - disp.scroll_to_tiles(a.x,a.y,b.x,b.y,display::ONSCREEN); + disp->scroll_to_tiles(a.x,a.y,b.x,b.y,display::ONSCREEN); } log_scope("unit_attack"); @@ -397,24 +421,29 @@ void unit_attack(display& disp, unit_map& units, const unit_map::iterator def = units.find(b); wassert(def != units.end()); - unit& defender = def->second; 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) { - unit_attack_ranged(disp, units, a, b, damage, attack,secondary_attack, update_display, swing); + unit_attack_ranged( a, b, damage, attack,secondary_attack, swing, hit_text); return; } int start_time = 500; int end_time = 0; + bool def_was_hidden = def->second.get_hidden(); + def->second.set_hidden(true); + unit defender = def->second; + disp->place_temporary_unit(defender,b); + defender.set_hidden(false); - attacker.set_attacking(disp,a,damage,attack,secondary_attack,swing); + + attacker.set_attacking(*disp,a,damage,attack,secondary_attack,swing); start_time=minimum(start_time,attacker.get_animation()->get_begin_time()); end_time=attacker.get_animation()->get_end_time(); - defender.set_defending(disp,b,damage,&attack, secondary_attack, swing); + defender.set_defending(*disp,b,damage,&attack, secondary_attack, swing); start_time=minimum(start_time,defender.get_animation()->get_begin_time()); @@ -425,7 +454,7 @@ void unit_attack(display& disp, unit_map& units, leader = units.find(leader_loc); wassert(leader != units.end()); leader->second.set_facing(leader_loc.get_relative_dir(a)); - leader->second.set_leading(disp,leader_loc); + leader->second.set_leading(*disp,leader_loc); start_time=minimum(start_time,leader->second.get_animation()->get_begin_time()); } @@ -434,16 +463,17 @@ void unit_attack(display& disp, unit_map& units, get_adjacent_tiles(b,update_tiles); - attacker.restart_animation(disp,start_time); - defender.restart_animation(disp,start_time); - if(leader_loc.valid()) leader->second.restart_animation(disp,start_time); + attacker.restart_animation(*disp,start_time); + defender.restart_animation(*disp,start_time); + if(leader_loc.valid()) leader->second.restart_animation(*disp,start_time); int animation_time = start_time; - bool played_center = false; + bool sound_played = false; while(!hide && ( !attacker.get_animation()->animation_would_finish() || !defender.get_animation()->animation_would_finish() || - (leader_loc.valid() && !leader->second.get_animation()->animation_would_finish() )) + (leader_loc.valid() && !leader->second.get_animation()->animation_would_finish() ) || + damage > 0) ){ double pos = 0.0; @@ -457,31 +487,134 @@ void unit_attack(display& disp, unit_map& units, if(attacker.state() != unit::STATE_STANDING && pos > 0.0) { attacker.set_offset(pos*0.6); } - if(!played_center && animation_time >= 0) { - played_center=true; - if(damage > 0 && !hide) { - sound::play_sound(def->second.get_hit_sound()); - disp.float_label(b,lexical_cast(damage),255,0,0); - disp.invalidate_unit(); - } + if(!sound_played && animation_time > 0) { + sound_played = true; + std::string text ; + if(damage) text = lexical_cast(damage); + if(!hit_text.empty()) text = text + "\n" + hit_text; + sound::play_sound(defender.get_hit_sound()); + disp->float_label(b,text,255,0,0); + disp->invalidate_unit(); } - disp.invalidate(b); - disp.invalidate(a); - if(leader_loc.valid()) disp.invalidate(leader_loc); - disp.draw(); + if(damage > 0 && animation_time > 0) { + defender.take_hit(1); + damage--; + disp->invalidate_unit(); + } + disp->invalidate(b); + disp->invalidate(a); + if(leader_loc.valid()) disp->invalidate(leader_loc); + disp->draw(); events::pump(); if(attacker.get_animation()->animation_finished()) { attacker.set_offset(0.0); } - disp.delay(10); + disp->delay(10); animation_time = attacker.get_animation()->get_animation_time(); } - if(leader_loc.valid()) leader->second.set_standing(disp,leader_loc); - att->second.set_standing(disp,a); - def->second.set_standing(disp,b); + if(leader_loc.valid()) leader->second.set_standing(*disp,leader_loc); + att->second.set_standing(*disp,a); + def->second.set_standing(*disp,b); + def->second.set_hidden(def_was_hidden); + disp->remove_temporary_unit(); +} + + +void unit_recruited(gamemap::location& loc) +{ + display* disp = play_controller::get_singleton()->get_display(); + if(!disp || disp->update_locked() ||disp->fogged(loc.x,loc.y)) return; + unit_map::iterator u = disp->get_units().find(loc); + if(u == disp->get_units().end()) return; + + u->second.set_hidden(true); + disp->scroll_to_tile(loc.x,loc.y,display::ONSCREEN); + disp->draw(); + u->second.set_recruited(*disp,loc); + u->second.set_hidden(false); + while(!u->second.get_animation()->animation_finished()) { + + disp->invalidate(loc); + disp->draw(); + events::pump(); + disp->delay(10); + } + u->second.set_standing(*disp,loc); +} + +void unit_healing(unit& healed_p,gamemap::location& healed_loc, std::vector healers, int healing) +{ + display* disp = play_controller::get_singleton()->get_display(); + if(!disp || disp->update_locked() || disp->fogged(healed_loc.x,healed_loc.y)) return; + if(healing==0) return; + // This is all the pretty stuff. + int start_time = INT_MAX; + disp->scroll_to_tile(healed_loc.x, healed_loc.y, display::ONSCREEN); + disp->select_hex(healed_loc); + unit healed = healed_p; + bool was_hidden = healed.get_hidden(); + healed_p.set_hidden(true); + disp->place_temporary_unit(healed,healed_loc); + healed.set_hidden(false); + + for(std::vector::iterator heal_anim_it = healers.begin(); heal_anim_it != healers.end(); ++heal_anim_it) { + (*heal_anim_it)->second.set_facing((*heal_anim_it)->first.get_relative_dir(healed_loc)); + (*heal_anim_it)->second.set_healing(*disp,(*heal_anim_it)->first,healing); + start_time = minimum((*heal_anim_it)->second.get_animation()->get_begin_time(),start_time); + } + if (healing < 0) { + healed.set_poisoned(*disp,healed_loc, -healing); + start_time = minimum(start_time, healed.get_animation()->get_begin_time()); + // FIXME + sound::play_sound("poison.ogg"); + disp->float_label(healed_loc, lexical_cast(-healing), 255,0,0); + } else { + healed.set_healed(*disp,healed_loc, healing); + start_time = minimum(start_time, healed.get_animation()->get_begin_time()); + sound::play_sound("heal.wav"); + disp->float_label(healed_loc, lexical_cast(healing), 0,255,0); + } + disp->draw(); + events::pump(); + // restart all anims in a synchronized way + healed.restart_animation(*disp, start_time); + for(std::vector::iterator heal_reanim_it = healers.begin(); heal_reanim_it != healers.end(); ++heal_reanim_it) { + (*heal_reanim_it)->second.restart_animation(*disp, start_time); + } + + bool finished; + do { + finished = (healed.get_animation()->animation_finished() && healing==0); + disp->invalidate(healed_loc); + for(std::vector::iterator heal_fanim_it = healers.begin(); heal_fanim_it != healers.end(); ++heal_fanim_it) { + finished &= (*heal_fanim_it)->second.get_animation()->animation_finished(); + disp->invalidate((*heal_fanim_it)->first); + } + // TODO : adapt HP change speed to turbo_speed + if(healing > 0) { + healed.heal(1); + healing--; + } else if (healing < 0) { + healed.take_hit(1); + healing++; + } + disp->draw(); + events::pump(); + disp->delay(10); + } while (!finished); + + healed_p.set_standing(*disp,healed_loc); + healed_p.set_hidden(was_hidden); + disp->remove_temporary_unit(); + for(std::vector::iterator heal_sanim_it = healers.begin(); heal_sanim_it != healers.end(); ++heal_sanim_it) { + (*heal_sanim_it)->second.set_standing(*disp,(*heal_sanim_it)->first); + } + + disp->update_display(); + events::pump(); } } // end unit display namespace diff --git a/src/unit_display.hpp b/src/unit_display.hpp index b99757b5025..53b3f919b86 100644 --- a/src/unit_display.hpp +++ b/src/unit_display.hpp @@ -17,7 +17,6 @@ #include "map.hpp" class attack_type; -class display; class team; class unit; class unit_map; @@ -27,25 +26,30 @@ class unit_map; ///attacking, and dying namespace unit_display { -bool unit_visible_on_path(display& disp, const std::vector& path, const unit& u, const unit_map& units, const std::vector& teams); +bool unit_visible_on_path( const std::vector& path, const unit& u, const unit_map& units, const std::vector& teams); ///a function to display a unit moving along a given path -void move_unit(display& disp, const gamemap& map, const std::vector& path, unit& u, const unit_map& units, const std::vector& teams); +void move_unit( const gamemap& map, const std::vector& path, unit& u, const std::vector& teams); ///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, unit& u, const attack_type* attack=NULL, const attack_type*secondary_attack=NULL, unit * winner=NULL); +void unit_die( const gamemap::location& loc, unit& u, const attack_type* attack=NULL, const attack_type*secondary_attack=NULL, unit * winner=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 ///displayed if the unit dies. ///true is returned if the defending unit is dead, and should be removed from the ///playing field. -void unit_attack(display& disp, unit_map& units, +void unit_attack( const gamemap::location& a, const gamemap::location& b, int damage, const attack_type& attack, const attack_type* secondary_attack, - bool update_display, int swing); + int swing,std::string hit_text); +void unit_recruited(gamemap::location& loc); + +// set healer_loc to an invalid location if there are no healers +// this will use a poisoning anim if healing<0 +void unit_healing(unit& healed,gamemap::location& healed_loc, std::vector healers, int healing); } #endif diff --git a/src/unit_types.cpp b/src/unit_types.cpp index 7c50ad04034..0bce467bdd7 100644 --- a/src/unit_types.cpp +++ b/src/unit_types.cpp @@ -731,7 +731,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types, healed_animations_.push_back(healed_animation(**healed_anim)); } if(healed_animations_.empty()) { - healed_animations_.push_back(healed_animation(0,unit_frame(image(),240,"1.0","",display::rgb(255,255,255),"0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30"))); + healed_animations_.push_back(healed_animation(0,unit_frame(image(),240,"1.0","",display::rgb(255,255,255),"0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30"))); // always have a healed animation } expanded_cfg = unit_animation::prepare_animation(cfg,"poison_anim");