34 #define LOG_DP LOG_STREAM(info, display) 46 std::string number_and_text(
int number,
const std::string& text)
52 std::ostringstream result;
57 result << std::string((text.size()+1)/2,
' ') << number <<
'\n' << text;
91 animator.
add_animation(temp_unit.shared_from_this(),
"pre_teleport",
a);
105 animator.
add_animation(temp_unit.shared_from_this(),
"post_teleport",
b);
134 unsigned int step_num,
135 unsigned int step_left,
143 temp_unit->set_location(a);
147 false,
"",{0,0,0},unit_animation::hit_type::INVALID,
nullptr,
nullptr,step_left);
161 target_time -= target_time%200;
166 bool do_not_show_anims(
display* disp)
179 can_draw_(disp_ && !disp_->video().update_locked() &&
180 !disp_->video().faked() && path.
size() > 1),
182 force_scroll_(force_scroll),
184 wait_until_(INT_MIN),
196 assert(!
path_.empty());
222 if (
disp_ ==
nullptr )
301 u->anim_comp().set_standing(
false);
338 path_index = std::min(path_index,
path_.size()-1);
344 std::vector<map_location> locs;
346 locs.push_back(
path_[current_]);
348 locs.push_back(
path_[current_+1]);
372 move_unit_between(
path_[current_],
path_[current_+1],
376 else if (
path_[current_] !=
path_[current_+1] )
377 teleport_unit_between(
path_[current_],
path_[current_+1],
384 u->anim_comp().set_standing(
false);
444 u->anim_comp().set_standing(
true);
473 mousehandler->invalidate_reachmap();
484 u->anim_comp().set_standing(
true);
513 unit_mover mover(path, animate, force_scroll);
533 animator.
add_animation(attacker.shared_from_this(),
"draw_weapon",loc,defender_loc,0,
true,
"",{0,0,0},unit_animation::hit_type::HIT,attack,secondary_attack,0);
535 animator.
add_animation(defender,
"draw_weapon",defender_loc,loc,0,
true,
"",{0,0,0},unit_animation::hit_type::MISS,secondary_attack,attack,0);
552 animator.
add_animation(primary_unit,
"sheath_weapon",primary_loc,secondary_loc,0,
true,
"",{0,0,0},unit_animation::hit_type::INVALID,primary_attack,secondary_attack,0);
555 animator.
add_animation(secondary_unit,
"sheath_weapon",secondary_loc,primary_loc,0,
true,
"",{0,0,0},unit_animation::hit_type::INVALID,secondary_attack,primary_attack,0);
558 if(primary_unit || secondary_unit) {
563 primary_unit->anim_comp().set_standing();
566 secondary_unit->anim_comp().set_standing();
582 animator.
add_animation(loser.shared_from_this(),
"death",loc,winner_loc,0,
false,
"",{0,0,0},unit_animation::hit_type::KILL,attack,secondary_attack,0);
585 animator.
add_animation(winner,
"victory",winner_loc,loc,0,
true,
"",{0,0,0},
586 unit_animation::hit_type::KILL,secondary_attack,attack,0);
594 mousehandler->invalidate_reachmap();
602 int swing,
const std::string& hit_text,
int drain_amount,
const std::string& att_text,
const std::vector<std::string>* extra_hit_sounds)
617 const unit& attacker = *att;
621 unit &defender = *def;
622 int def_hitpoints = defender.hitpoints();
628 std::string text = number_and_text(damage, hit_text);
629 std::string text_2 = number_and_text(std::abs(drain_amount), att_text);
631 unit_animation::hit_type hit_type;
632 if(damage >= defender.hitpoints()) {
633 hit_type = unit_animation::hit_type::KILL;
634 }
else if(damage > 0) {
635 hit_type = unit_animation::hit_type::HIT;
637 hit_type = unit_animation::hit_type::MISS;
642 animator.
add_animation(attacker.shared_from_this(),
"attack", att->get_location(), def->get_location(), damage,
true, text_2,
643 (drain_amount >= 0) ?
color_t(0, 255, 0) :
color_t(255, 0, 0), hit_type, attack.shared_from_this(),
644 secondary_attack, swing);
647 const unit_animation* defender_anim = def->anim_comp().choose_animation(*disp, def->get_location(),
"defend",
648 att->get_location(), damage, hit_type, attack.shared_from_this(), secondary_attack, swing);
650 animator.
add_animation(defender.shared_from_this(), defender_anim, def->get_location(),
true, text, {255, 0, 0});
652 for(
const unit_ability& ability : attacker.get_abilities_weapons(
"leadership", attack.shared_from_this(), secondary_attack)) {
653 if(ability.teacher_loc == a) {
657 if(ability.teacher_loc == b) {
662 assert(leader.
valid());
663 leader->set_facing(ability.teacher_loc.get_relative_dir(a));
665 att->get_location(), damage,
true,
"", {0,0,0},
666 hit_type, attack.shared_from_this(), secondary_attack, swing);
669 for(
const unit_ability& ability : defender.get_abilities_weapons(
"resistance", secondary_attack, attack.shared_from_this())) {
670 if(ability.teacher_loc == a) {
674 if(ability.teacher_loc == b) {
679 assert(helper.
valid());
680 helper->set_facing(ability.teacher_loc.get_relative_dir(b));
682 def->get_location(), damage,
true,
"", {0,0,0},
683 hit_type, attack.shared_from_this(), secondary_attack, swing);
689 int damage_left = damage;
690 bool extra_hit_sounds_played =
false;
691 while(damage_left > 0 && !animator.
would_end()) {
692 if(!extra_hit_sounds_played && extra_hit_sounds !=
nullptr) {
693 for (std::string hit_sound : *extra_hit_sounds) {
696 extra_hit_sounds_played =
true;
700 if(step_left < 1) step_left = 1;
701 int removed_hp = damage_left/step_left ;
702 if(removed_hp < 1) removed_hp = 1;
703 defender.take_hit(removed_hp);
704 damage_left -= removed_hp;
709 def->anim_comp().start_animation(animator.
get_end_time(), defender_anim,
true);
711 def->set_hitpoints(def_hitpoints);
722 assert(leader != units.
end());
723 leader->anim_comp().set_standing();
730 assert(helper != units.
end());
731 helper->anim_comp().set_standing();
739 if(do_not_show_anims(disp) || (disp->
fogged(loc) && disp->
fogged(leader_loc))) {
748 const bool unit_visible = u->is_visible_to_team(viewing_team,
false);
751 const bool leader_visible = (leader != disp->
get_units().
end()) && leader->is_visible_to_team(viewing_team,
false);
759 if (leader_visible && unit_visible) {
761 }
else if (leader_visible) {
763 }
else if (unit_visible) {
770 if (leader_visible) {
785 const std::string & extra_text)
789 const bool some_healer_is_unfogged =
790 (healers.end() != std::find_if_not(healers.begin(), healers.end(),
791 [&](
unit*
h) {
return disp->
fogged(
h->get_location()); }));
793 if(do_not_show_anims(disp) || (disp->
fogged(healed_loc) && !some_healer_is_unfogged)) {
802 for (
unit *
h : healers) {
803 h->set_facing(
h->get_location().get_relative_dir(healed_loc));
804 animator.
add_animation(
h->shared_from_this(),
"healing",
h->get_location(),
805 healed_loc, healing);
809 animator.
add_animation(healed.shared_from_this(),
"poisoned", healed_loc,
811 number_and_text(-healing, extra_text),
813 }
else if ( healing > 0 ) {
814 animator.
add_animation(healed.shared_from_this(),
"healed", healed_loc,
816 number_and_text(healing, extra_text),
819 animator.
add_animation(healed.shared_from_this(),
"healed", healed_loc,
821 extra_text, {0,255,0});
const map_location & mouseover_hex() const
void wait_for_end() const
virtual void select_hex(map_location hex)
void unit_draw_weapon(const map_location &loc, unit &attacker, const_attack_ptr attack, const_attack_ptr secondary_attack, const map_location &defender_loc, unit_ptr defender)
Play a pre-fight animation First unit is the attacker, second unit the defender.
bool update_locked() const
Whether the screen has been 'locked' or not.
static display * get_singleton()
Returns the display object if a display object exists.
const team & get_team(int side) const
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
void unit_sheath_weapon(const map_location &primary_loc, unit_ptr primary_unit, const_attack_ptr primary_attack, const_attack_ptr secondary_attack, const map_location &secondary_loc, unit_ptr secondary_unit)
Play a post-fight animation Both unit can be set to null, only valid units will play their animation...
virtual const unit_map & units() const override
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
game_display *const disp_
This class represents a single unit of a specific type.
internal_ptr get_unit_ptr()
Get a copy of the internal unit pointer.
void invalidate_unit()
Function to invalidate that unit status displayed on the sidebar.
void set_location(const map_location &loc)
Sets this unit's map location.
const unit_map & get_units() const
unit_mover(const unit_mover &)=delete
virtual void draw()
Draws invalidated items.
void set_facing(map_location::DIRECTION dir) const
The this unit's facing.
std::shared_ptr< unit > unit_ptr
void update_display()
Copy the backbuffer to the framebuffer.
int get_animation_time_potential() const
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Contains a number of free functions which display units.
void wait_until(int animation_time) const
unit_ptr shown_unit_
The unit to be (re-)shown after an animation finishes.
This class stores all the data for a single 'side' (in game nomenclature).
Data typedef for unit_ability_list.
static mouse_handler * get_singleton()
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
void finish(unit_ptr u, map_location::DIRECTION dir=map_location::NDIRECTIONS)
Finishes the display of movement for the supplied unit.
bool tile_fully_on_screen(const map_location &loc) const
Check if a tile is fully visible on screen.
void update_shown_unit()
Switches the display back to *shown_unit_ after animating.
fake_unit_manager * fake_units
A class to encapsulate the steps of drawing a unit's move.
void unit_healing(unit &healed, const std::vector< unit *> &healers, int healing, const std::string &extra_text)
This will use a poisoning anim if healing<0.
const std::vector< map_location > & path_
void wait_for_anims()
Waits for the final animation of the most recent proceed_to() to finish.
int wait_until_
The animation potential to wait until.
static map_location::DIRECTION se
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Encapsulates the map of the game.
void add_animation(unit_const_ptr animated_unit, const unit_animation *animation, const map_location &src=map_location::null_location(), bool with_bars=false, const std::string &text="", const color_t text_color={0, 0, 0})
unit_iterator find(std::size_t id)
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
pointer get_shared_ptr() const
This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax...
void replace_temporary(unit_ptr u)
Makes the temporary unit used by this match the supplied unit.
unit_animation_component & anim_comp() const
void scroll_to_tile(const map_location &loc, SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true, bool force=true)
Scroll such that location loc is on-screen.
void scroll_to_tiles(map_location loc1, map_location loc2, SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true, double add_spacing=0.0, bool force=true)
Scroll such that location loc1 is on-screen.
void proceed_to(unit_ptr u, std::size_t path_index, bool update=false, bool wait=true)
Visually moves a unit from the last hex we drew to the one specified by path_index.
void unit_die(const map_location &loc, unit &loser, const_attack_ptr attack, const_attack_ptr secondary_attack, const map_location &winner_loc, unit_ptr winner)
Show a unit fading out.
void replace_anim_if_invalid(unit_const_ptr animated_unit, const std::string &event, const map_location &src=map_location::null_location(), const map_location &dst=map_location::null_location(), const int value=0, bool with_bars=false, const std::string &text="", const color_t text_color={0, 0, 0}, const unit_animation::hit_type hit_type=unit_animation::hit_type::INVALID, const_attack_ptr attack=nullptr, const_attack_ptr second_attack=nullptr, int value2=0)
unit_map::iterator find_unit(const map_location &loc)
void start(unit_ptr u)
Initiates the display of movement for the supplied unit.
#define log_scope(description)
const display_context & get_disp_context() const
DIRECTION
Valid directions which can be moved in our hexagonal world.
bool is_visible_to_team(const team &team, bool const see_all=true) const
void reset_helpers(const unit *attacker, const unit *defender)
int get_animation_time() const
const map_location & get_location() const
The current map location this unit is at.
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Standard logging facilities (interface).
fake_unit_ptr temp_unit_ptr_
CVideo & video()
Gets the underlying screen object.
static const map_location & null_location()
Container associating units to locations.
void set_standing(bool with_bars=true)
Sets the animation state to standing.
unit_ability_list get_abilities(const std::string &tag_name, const map_location &loc) const
Gets the unit's active abilities of a particular type if it were on a specified location.
void unit_attack(display *disp, game_board &board, const map_location &a, const map_location &b, int damage, const attack_type &attack, const_attack_ptr secondary_attack, int swing, const std::string &hit_text, int drain_amount, const std::string &att_text, const std::vector< std::string > *extra_hit_sounds)
Make the unit on tile 'a' attack the unit on tile 'b'.
std::shared_ptr< const attack_type > const_attack_ptr
void display_unit_hex(map_location hex)
Change the unit to be displayed in the sidebar.
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
Display units performing various actions: moving, attacking, and dying.
void move_unit(const std::vector< map_location > &path, unit_ptr u, bool animate, map_location::DIRECTION dir, bool force_scroll)
Display a unit moving along a given path.
static game_display * get_singleton()