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;
90 animator.
add_animation(temp_unit.shared_from_this(),
"pre_teleport",a);
104 animator.
add_animation(temp_unit.shared_from_this(),
"post_teleport",
b);
129 std::chrono::milliseconds move_unit_between(
const map_location& a,
132 unsigned int step_num,
133 unsigned int step_left,
138 return std::chrono::milliseconds::min();
145 false,
"",{0,0,0},strike_result::type::invalid,
nullptr,
nullptr,step_left);
158 target_time += 200ms;
159 target_time -= target_time % 200ms;
164 bool do_not_show_anims(
display* disp)
178 force_scroll_(force_scroll),
180 wait_until_(std::
chrono::milliseconds::min()),
192 assert(!
path_.empty());
218 if (
disp_ ==
nullptr )
297 u->anim_comp().set_standing(
false);
334 path_index = std::min(path_index,
path_.size()-1);
340 std::vector<map_location> locs;
380 u->anim_comp().set_standing(
false);
395 if (
wait_until_ == std::chrono::milliseconds::max() )
398 else if (
wait_until_ != std::chrono::milliseconds::min() ) {
440 u->anim_comp().set_standing(
true);
469 mousehandler->invalidate_reachmap();
480 u->anim_comp().set_standing(
true);
529 animator.
add_animation(attacker.shared_from_this(),
"draw_weapon",loc,defender_loc,0,
true,
"",{0,0,0},strike_result::type::hit,attack,secondary_attack,0);
531 animator.
add_animation(defender,
"draw_weapon",defender_loc,loc,0,
true,
"",{0,0,0},strike_result::type::miss,secondary_attack,attack,0);
548 animator.
add_animation(primary_unit,
"sheath_weapon",primary_loc,secondary_loc,0,
true,
"",{0,0,0},strike_result::type::invalid,primary_attack,secondary_attack,0);
551 animator.
add_animation(secondary_unit,
"sheath_weapon",secondary_loc,primary_loc,0,
true,
"",{0,0,0},strike_result::type::invalid,secondary_attack,primary_attack,0);
554 if(primary_unit || secondary_unit) {
559 primary_unit->anim_comp().set_standing();
562 secondary_unit->anim_comp().set_standing();
578 animator.
add_animation(loser.shared_from_this(),
"death",loc,winner_loc,0,
false,
"",{0,0,0},strike_result::type::kill,attack,secondary_attack,0);
581 animator.
add_animation(winner,
"victory",winner_loc,loc,0,
true,
"",{0,0,0},
582 strike_result::type::kill,secondary_attack,attack,0);
590 mousehandler->invalidate_reachmap();
598 int swing,
const std::string& hit_text,
int drain_amount,
599 const std::string& att_text,
600 const std::vector<std::string>* extra_hit_sounds,
616 const unit& attacker = *att;
620 unit &defender = *def;
621 int def_hitpoints = defender.
hitpoints();
623 auto ctx = weapon->
specials_context(attacker.shared_from_this(), defender.shared_from_this(), a,
b, attacking, secondary_attack);
624 utils::optional<decltype(ctx)> opp_ctx;
626 if(secondary_attack) {
627 opp_ctx.emplace(secondary_attack->specials_context(defender.shared_from_this(), attacker.shared_from_this(),
b, a, !attacking, weapon));
631 def->set_facing(
b.get_relative_dir(a));
634 std::string text = number_and_text(damage, hit_text);
635 std::string text_2 = number_and_text(std::abs(drain_amount), att_text);
639 hit_type = strike_result::type::kill;
640 }
else if(damage > 0) {
641 hit_type = strike_result::type::hit;
643 hit_type = strike_result::type::miss;
648 animator.
add_animation(attacker.shared_from_this(),
"attack", att->get_location(), def->get_location(), damage,
true, text_2,
649 (drain_amount >= 0) ?
color_t(0, 255, 0) :
color_t(255, 0, 0), hit_type, weapon,
650 secondary_attack, swing);
653 const unit_animation* defender_anim = def->anim_comp().choose_animation(def->get_location(),
"defend",
654 att->get_location(), damage, hit_type, weapon, secondary_attack, swing);
656 animator.
add_animation(defender.shared_from_this(), defender_anim, def->get_location(),
true, text, {255, 0, 0});
661 if(ability.teacher_loc == a) {
665 if(ability.teacher_loc ==
b) {
670 assert(leader.
valid());
671 leader->set_facing(ability.teacher_loc.get_relative_dir(a));
672 leader->anim_comp().invalidate(*disp);
674 att->get_location(), damage,
true,
"", {0,0,0},
675 hit_type, weapon, secondary_attack, swing);
679 if(ability.teacher_loc == a) {
683 if(ability.teacher_loc ==
b) {
688 assert(helper.
valid());
689 helper->set_facing(ability.teacher_loc.get_relative_dir(
b));
691 def->get_location(), damage,
true,
"", {0,0,0},
692 hit_type, weapon, secondary_attack, swing);
697 abilities.
append(weapon->get_weapon_ability(special));
701 if(ability.teacher_loc == a) {
705 if(ability.teacher_loc ==
b) {
709 bool leading_playable =
false;
710 bool helping_playable =
false;
711 for(
const unit_ability& leader_list : leadership_list) {
712 if(ability.teacher_loc == leader_list.teacher_loc) {
713 leading_playable =
true;
718 for(
const unit_ability& helper_list : resistance_list) {
719 if(ability.teacher_loc == helper_list.teacher_loc) {
720 helping_playable =
true;
726 assert(leader.
valid());
727 leader->set_facing(ability.teacher_loc.get_relative_dir(a));
729 att->get_location(), damage, hit_type, weapon, secondary_attack, swing) && leading_playable){
733 def->get_location(), damage, hit_type, weapon, secondary_attack, swing) && helping_playable){
737 att->get_location(), damage,
true,
"", {0,0,0},
738 hit_type, weapon, secondary_attack, swing);
744 int damage_left = damage;
745 bool extra_hit_sounds_played =
false;
746 while(damage_left > 0 && !animator.
would_end()) {
747 if(!extra_hit_sounds_played && extra_hit_sounds !=
nullptr) {
748 for (std::string hit_sound : *extra_hit_sounds) {
751 extra_hit_sounds_played =
true;
755 if(step_left < 1) step_left = 1;
756 int removed_hp = damage_left/step_left ;
757 if(removed_hp < 1) removed_hp = 1;
759 damage_left -= removed_hp;
764 def->anim_comp().start_animation(animator.
get_end_time(), defender_anim,
true);
766 def->set_hitpoints(def_hitpoints);
781 assert(leader != units.
end());
782 leader->anim_comp().set_standing();
793 assert(helper != units.
end());
794 helper->anim_comp().set_standing();
802 if(do_not_show_anims(disp) || (disp->
fogged(loc) && disp->
fogged(leader_loc))) {
810 if(u == units.
end())
return;
811 const bool unit_visible = u->is_visible_to_team(viewing_team,
false);
814 const bool leader_visible = (leader != units.
end()) && leader->is_visible_to_team(viewing_team,
false);
820 u->set_hidden(
false);
824 if (leader_visible && unit_visible) {
826 }
else if (leader_visible) {
828 }
else if (unit_visible) {
833 if(leader != units.
end()) {
835 if (leader_visible) {
848 const std::string & extra_text)
852 const bool some_healer_is_unfogged =
853 (healers.end() != std::find_if_not(healers.begin(), healers.end(),
854 [&](
unit*
h) { return disp->fogged(h->get_location()); }));
856 if(do_not_show_anims(disp) || (disp->
fogged(healed_loc) && !some_healer_is_unfogged)) {
865 for (
unit *
h : healers) {
866 h->set_facing(
h->get_location().get_relative_dir(healed_loc));
867 animator.
add_animation(
h->shared_from_this(),
"healing",
h->get_location(),
868 healed_loc, healing);
872 animator.
add_animation(healed.shared_from_this(),
"poisoned", healed_loc,
874 number_and_text(-healing, extra_text),
876 }
else if ( healing > 0 ) {
877 animator.
add_animation(healed.shared_from_this(),
"healed", healed_loc,
879 number_and_text(healing, extra_text),
882 animator.
add_animation(healed.shared_from_this(),
"healed", healed_loc,
884 extra_text, {0,255,0});
specials_context_t specials_context(unit_const_ptr self, unit_const_ptr other, const map_location &unit_loc, const map_location &other_loc, bool attacking, const_attack_ptr other_attack) const
virtual const unit_map & units() const =0
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
const team & viewing_team() const
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
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.
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
bool tile_fully_on_screen(const map_location &loc) const
Check if a tile is fully visible 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.
const display_context & context() const
static display * get_singleton()
Returns the display object if a display object exists.
const map_location & mouseover_hex() const
virtual void select_hex(map_location hex)
static mouse_handler * get_singleton()
Holds a temporary unit that can be drawn on the map without being placed in the unit_map.
internal_ptr get_unit_ptr()
Get a copy of the internal unit pointer.
unit_map::iterator find_unit(const map_location &loc)
virtual const unit_map & units() const override
void display_unit_hex(map_location hex)
Change the unit to be displayed in the sidebar.
void invalidate_unit()
Function to invalidate that unit status displayed on the sidebar.
static game_display * get_singleton()
bool is_skipping_replay() const
This class stores all the data for a single 'side' (in game nomenclature).
bool is_enemy(int n) const
void append(const unit_ability_list &other)
Appends the abilities from other to this, ignores other.loc()
void set_standing(bool with_bars=true)
Sets the animation state to standing.
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 strike_result::type hit_type=strike_result::type::invalid, const_attack_ptr attack=nullptr, const_attack_ptr second_attack=nullptr, int value2=0)
std::chrono::milliseconds get_animation_time_potential() const
std::chrono::milliseconds get_animation_time() const
bool has_animation(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, const strike_result::type hit_type=strike_result::type::invalid, const_attack_ptr attack=nullptr, const_attack_ptr second_attack=nullptr, int value2=0) const
has_animation : return an boolean value if animated unit present and have animation specified,...
void wait_for_end() const
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})
std::chrono::milliseconds get_end_time() const
void wait_until(const std::chrono::milliseconds &animation_time) const
A class to encapsulate the steps of drawing a unit's move.
void wait_for_anims()
Waits for the final animation of the most recent proceed_to() to finish.
void start(unit_ptr u)
Initiates the display of movement for the supplied unit.
void finish(unit_ptr u, map_location::direction dir=map_location::direction::indeterminate)
Finishes the display of movement for the supplied unit.
unit_ptr shown_unit_
The unit to be (re-)shown after an animation finishes.
void replace_temporary(unit_ptr u)
Makes the temporary unit used by this match the supplied unit.
game_display *const disp_
void update_shown_unit()
Switches the display back to *shown_unit_ after animating.
std::chrono::milliseconds wait_until_
The animation potential to wait until.
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.
const std::vector< map_location > & path_
unit_mover(const unit_mover &)=delete
fake_unit_ptr temp_unit_ptr_
Container associating units to locations.
unit_iterator find(std::size_t id)
This class represents a single unit of a specific type.
unit_ability_list get_abilities_weapons(const std::string &tag_name, const map_location &loc, const_attack_ptr weapon=nullptr, const_attack_ptr opp_weapon=nullptr) const
bool is_visible_to_team(const team &team, bool const see_all=true) const
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.
const std::set< std::string > & checking_tags() const
int hitpoints() const
The current number of hitpoints this unit has.
bool take_hit(int damage)
Damage the unit.
unit_animation_component & anim_comp() const
const map_location & get_location() const
The current map location this unit is at.
void set_facing(map_location::direction dir) const
The this unit's facing.
void set_location(const map_location &loc)
Sets this unit's map location.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Standard logging facilities (interface).
#define log_scope(description)
void pump()
Process all events currently in the queue.
fake_unit_manager * fake_units
play_controller * controller
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Contains a number of free functions which display units.
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.
void unit_recruited(const map_location &loc, const map_location &leader_loc)
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.
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 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.
void reset_helpers(const unit *attacker, const unit *defender)
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, bool attacking)
Make the unit on tile 'a' attack the unit on tile 'b'.
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.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
bool headless()
The game is running headless.
std::shared_ptr< const attack_type > const_attack_ptr
std::shared_ptr< unit > unit_ptr
#define ON_SCOPE_EXIT(...)
Run some arbitrary code (a lambda) when the current scope exits The lambda body follows this header,...
The basic class for representing 8-bit RGB or RGBA colour values.
Encapsulates the map of the game.
direction
Valid directions which can be moved in our hexagonal world.
direction get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
static const map_location & null_location()
Data typedef for unit_ability_list.
pointer get_shared_ptr() const
This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax...
Display units performing various actions: moving, attacking, and dying.