35 #define LOG_DP LOG_STREAM(info, display)
47 std::string number_and_text(
int number,
const std::string& text)
53 std::ostringstream result;
58 result << std::string((text.size()+1)/2,
' ') << number <<
'\n' << text;
91 animator.
add_animation(temp_unit.shared_from_this(),
"pre_teleport",a);
106 animator.
add_animation(temp_unit.shared_from_this(),
"post_teleport",
b);
132 std::chrono::milliseconds move_unit_between(
const map_location& a,
135 unsigned int step_num,
136 unsigned int step_left,
141 return std::chrono::milliseconds::min();
148 false,
"",{0,0,0},strike_result::type::invalid,
nullptr,
nullptr,step_left);
161 target_time += 200ms;
162 target_time -= target_time % 200ms;
167 bool do_not_show_anims(
display* disp)
181 force_scroll_(force_scroll),
183 wait_until_(std::
chrono::milliseconds::min()),
195 assert(!
path_.empty());
221 if (
disp_ ==
nullptr )
266 u->anim_comp().reset_affect_adjacent(*
disp_);
301 u->anim_comp().set_standing(
false);
338 path_index = std::min(path_index,
path_.size()-1);
344 std::vector<map_location> locs;
384 u->anim_comp().set_standing(
false);
399 if (
wait_until_ == std::chrono::milliseconds::max() )
402 else if (
wait_until_ != std::chrono::milliseconds::min() ) {
444 u->anim_comp().set_standing(
true);
471 u->anim_comp().reset_affect_adjacent(*
disp_);
474 mousehandler->invalidate_reachmap();
485 u->anim_comp().set_standing(
true);
534 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);
536 animator.
add_animation(defender,
"draw_weapon",defender_loc,
loc,0,
true,
"",{0,0,0},strike_result::type::miss,secondary_attack,attack,0);
553 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);
556 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);
559 if(primary_unit || secondary_unit) {
564 primary_unit->anim_comp().set_standing();
567 secondary_unit->anim_comp().set_standing();
583 animator.
add_animation(loser.shared_from_this(),
"death",
loc,winner_loc,0,
false,
"",{0,0,0},strike_result::type::kill,attack,secondary_attack,0);
586 animator.
add_animation(winner,
"victory",winner_loc,
loc,0,
true,
"",{0,0,0},
587 strike_result::type::kill,secondary_attack,attack,0);
595 mousehandler->invalidate_reachmap();
604 int swing,
const std::string& hit_text,
int drain_amount,
605 const std::string& att_text,
606 const std::vector<std::string>* extra_hit_sounds,
622 const unit& attacker = *att;
626 unit &defender = *def;
627 int def_hitpoints = defender.
hitpoints();
629 auto ctx = weapon->
specials_context(attacker.shared_from_this(), defender.shared_from_this(), a,
b, attacking, secondary_attack);
630 utils::optional<decltype(ctx)> opp_ctx;
632 if(secondary_attack) {
633 opp_ctx.emplace(secondary_attack->specials_context(defender.shared_from_this(), attacker.shared_from_this(),
b, a, !attacking, weapon));
637 def->set_facing(
b.get_relative_dir(a));
640 std::string text = number_and_text(damage, hit_text);
641 std::string text_2 = number_and_text(std::abs(drain_amount), att_text);
645 hit_type = strike_result::type::kill;
646 }
else if(damage > 0) {
647 hit_type = strike_result::type::hit;
649 hit_type = strike_result::type::miss;
654 animator.
add_animation(attacker.shared_from_this(),
"attack", att->get_location(), def->get_location(), damage,
true, text_2,
655 (drain_amount >= 0) ?
color_t(0, 255, 0) :
color_t(255, 0, 0), hit_type, weapon,
656 secondary_attack, swing);
659 const unit_animation* defender_anim = def->anim_comp().choose_animation(def->get_location(),
"defend",
660 att->get_location(), damage, hit_type, weapon, secondary_attack, swing);
662 animator.
add_animation(defender.shared_from_this(), defender_anim, def->get_location(),
true, text, {255, 0, 0});
667 if(ability.teacher_loc == a) {
671 if(ability.teacher_loc ==
b) {
676 assert(leader.
valid());
677 leader->set_facing(ability.teacher_loc.get_relative_dir(a));
678 leader->anim_comp().invalidate(*disp);
680 att->get_location(), damage,
true,
"", {0,0,0},
681 hit_type, weapon, secondary_attack, swing);
685 if(ability.teacher_loc == a) {
689 if(ability.teacher_loc ==
b) {
694 assert(helper.
valid());
695 helper->set_facing(ability.teacher_loc.get_relative_dir(
b));
697 def->get_location(), damage,
true,
"", {0,0,0},
698 hit_type, weapon, secondary_attack, swing);
702 for(
auto& special : abilities_list::all_weapon_tags()) {
703 abilities.
append(weapon->get_weapon_ability(special));
707 if(ability.teacher_loc == a) {
711 if(ability.teacher_loc ==
b) {
715 bool leading_playable =
false;
716 bool helping_playable =
false;
717 for(
const unit_ability& leader_list : leadership_list) {
718 if(ability.teacher_loc == leader_list.teacher_loc) {
719 leading_playable =
true;
724 for(
const unit_ability& helper_list : resistance_list) {
725 if(ability.teacher_loc == helper_list.teacher_loc) {
726 helping_playable =
true;
732 assert(leader.
valid());
733 leader->set_facing(ability.teacher_loc.get_relative_dir(a));
735 att->get_location(), damage, hit_type, weapon, secondary_attack, swing) && leading_playable){
739 def->get_location(), damage, hit_type, weapon, secondary_attack, swing) && helping_playable){
743 att->get_location(), damage,
true,
"", {0,0,0},
744 hit_type, weapon, secondary_attack, swing);
750 int damage_left = damage;
751 bool extra_hit_sounds_played =
false;
752 while(damage_left > 0 && !animator.
would_end()) {
753 if(!extra_hit_sounds_played && extra_hit_sounds !=
nullptr) {
754 for (std::string hit_sound : *extra_hit_sounds) {
757 extra_hit_sounds_played =
true;
761 if(step_left < 1) step_left = 1;
762 int removed_hp = damage_left/step_left ;
763 if(removed_hp < 1) removed_hp = 1;
765 damage_left -= removed_hp;
770 def->anim_comp().start_animation(animator.
get_end_time(), defender_anim,
true);
772 def->set_hitpoints(def_hitpoints);
782 for(
auto& special : abilities_list::all_weapon_tags()) {
787 assert(leader != units.
end());
788 leader->anim_comp().set_standing();
794 for(
auto& special : abilities_list::all_weapon_tags()) {
799 assert(helper != units.
end());
800 helper->anim_comp().set_standing();
808 if(do_not_show_anims(disp) || (disp->
fogged(
loc) && disp->
fogged(leader_loc))) {
816 if(u == units.
end())
return;
817 const bool unit_visible = u->is_visible_to_team(viewing_team,
false);
820 const bool leader_visible = (leader != units.
end()) && leader->is_visible_to_team(viewing_team,
false);
826 u->set_hidden(
false);
830 if (leader_visible && unit_visible) {
832 }
else if (leader_visible) {
834 }
else if (unit_visible) {
839 if(leader != units.
end()) {
841 if (leader_visible) {
846 u->anim_comp().reset_affect_adjacent(*disp);
855 const std::string & extra_text)
859 const bool some_healer_is_unfogged =
860 (healers.end() != std::find_if_not(healers.begin(), healers.end(),
861 [&](
unit*
h) { return disp->fogged(h->get_location()); }));
863 if(do_not_show_anims(disp) || (disp->
fogged(healed_loc) && !some_healer_is_unfogged)) {
872 for (
unit *
h : healers) {
873 h->set_facing(
h->get_location().get_relative_dir(healed_loc));
874 animator.
add_animation(
h->shared_from_this(),
"healing",
h->get_location(),
875 healed_loc, healing);
879 animator.
add_animation(healed.shared_from_this(),
"poisoned", healed_loc,
881 number_and_text(-healing, extra_text),
883 }
else if ( healing > 0 ) {
884 animator.
add_animation(healed.shared_from_this(),
"healed", healed_loc,
886 number_and_text(healing, extra_text),
889 animator.
add_animation(healed.shared_from_this(),
"healed", healed_loc,
891 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 reset_affect_adjacent(const unit_map &units)
Refresh map around unit if has ability with [affect_adjacent/distant] tag.
void set_standing(bool with_bars=true)
Sets the animation state to standing.
std::chrono::milliseconds get_animation_time_potential() const
std::chrono::milliseconds get_animation_time() const
bool has_animation(const 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 const_attack_ptr &attack=nullptr, const 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 replace_anim_if_invalid(const 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 const_attack_ptr &attack=nullptr, const const_attack_ptr &second_attack=nullptr, int value2=0)
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 finish(const unit_ptr &u, map_location::direction dir=map_location::direction::indeterminate)
Finishes the display of movement for the supplied unit.
void replace_temporary(const unit_ptr &u)
Makes the temporary unit used by this match the supplied unit.
void wait_for_anims()
Waits for the final animation of the most recent proceed_to() to finish.
unit_ptr shown_unit_
The unit to be (re-)shown after an animation finishes.
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(const 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 start(const unit_ptr &u)
Initiates the display of movement for the supplied unit.
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.
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, utils::span< map_location, 6 > 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_die(const map_location &loc, unit &loser, const const_attack_ptr &attack, const const_attack_ptr &secondary_attack, const map_location &winner_loc, const unit_ptr &winner)
Show a unit fading out.
void unit_draw_weapon(const map_location &loc, unit &attacker, const const_attack_ptr &attack, const const_attack_ptr &secondary_attack, const map_location &defender_loc, const unit_ptr &defender)
Play a pre-fight animation First unit is the attacker, second unit the defender.
void unit_attack(display *disp, game_board &board, const map_location &a, const map_location &b, int damage, const attack_type &attack, const 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 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 move_unit(const std::vector< map_location > &path, const unit_ptr &u, bool animate, map_location::direction dir, bool force_scroll)
Display a unit moving along a given path.
void unit_sheath_weapon(const map_location &primary_loc, const unit_ptr &primary_unit, const const_attack_ptr &primary_attack, const const_attack_ptr &secondary_attack, const map_location &secondary_loc, const 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)
std::size_t size(std::string_view 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.