36 #define LOG_DP LOG_STREAM(info, display)
48 std::string number_and_text(
int number,
const std::string& text)
54 std::ostringstream result;
59 result << std::string((text.size()+1)/2,
' ') << number <<
'\n' << text;
93 animator.
add_animation(temp_unit.shared_from_this(),
"pre_teleport",
a);
107 animator.
add_animation(temp_unit.shared_from_this(),
"post_teleport",
b);
135 unsigned int step_num,
136 unsigned int step_left,
148 false,
"",{0,0,0},strike_result::type::invalid,
nullptr,
nullptr,step_left);
162 target_time -= target_time%200;
167 bool do_not_show_anims(
display* disp)
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;
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);
533 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);
535 animator.
add_animation(defender,
"draw_weapon",defender_loc,loc,0,
true,
"",{0,0,0},strike_result::type::miss,secondary_attack,attack,0);
552 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);
555 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);
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},strike_result::type::kill,attack,secondary_attack,0);
585 animator.
add_animation(winner,
"victory",winner_loc,loc,0,
true,
"",{0,0,0},
586 strike_result::type::kill,secondary_attack,attack,0);
594 mousehandler->invalidate_reachmap();
602 int swing,
const std::string& hit_text,
int drain_amount,
603 const std::string& att_text,
604 const std::vector<std::string>* extra_hit_sounds,
620 const unit& attacker = *att;
624 unit &defender = *def;
625 int def_hitpoints = defender.
hitpoints();
627 auto ctx = weapon->
specials_context(attacker.shared_from_this(), defender.shared_from_this(),
a,
b, attacking, secondary_attack);
628 std::optional<decltype(ctx)> opp_ctx;
630 if(secondary_attack) {
631 opp_ctx.emplace(secondary_attack->specials_context(defender.shared_from_this(), attacker.shared_from_this(),
b,
a, !attacking, weapon));
634 att->set_facing(
a.get_relative_dir(
b));
635 def->set_facing(
b.get_relative_dir(
a));
638 std::string text = number_and_text(damage, hit_text);
639 std::string text_2 = number_and_text(std::abs(drain_amount), att_text);
643 hit_type = strike_result::type::kill;
644 }
else if(damage > 0) {
645 hit_type = strike_result::type::hit;
647 hit_type = strike_result::type::miss;
652 animator.
add_animation(attacker.shared_from_this(),
"attack", att->get_location(), def->get_location(), damage,
true, text_2,
653 (drain_amount >= 0) ?
color_t(0, 255, 0) :
color_t(255, 0, 0), hit_type, weapon,
654 secondary_attack, swing);
657 const unit_animation* defender_anim = def->anim_comp().choose_animation(def->get_location(),
"defend",
658 att->get_location(), damage, hit_type, weapon, secondary_attack, swing);
660 animator.
add_animation(defender.shared_from_this(), defender_anim, def->get_location(),
true, text, {255, 0, 0});
665 if(ability.teacher_loc ==
a) {
669 if(ability.teacher_loc ==
b) {
674 assert(leader.
valid());
675 leader->set_facing(ability.teacher_loc.get_relative_dir(
a));
676 leader->anim_comp().invalidate(*disp);
678 att->get_location(), damage,
true,
"", {0,0,0},
679 hit_type, weapon, secondary_attack, swing);
683 if(ability.teacher_loc ==
a) {
687 if(ability.teacher_loc ==
b) {
692 assert(helper.
valid());
693 helper->set_facing(ability.teacher_loc.get_relative_dir(
b));
695 def->get_location(), damage,
true,
"", {0,0,0},
696 hit_type, weapon, secondary_attack, swing);
701 abilities.
append(weapon->get_weapon_ability(special));
705 if(ability.teacher_loc ==
a) {
709 if(ability.teacher_loc ==
b) {
713 bool leading_playable =
false;
714 bool helping_playable =
false;
715 for(
const unit_ability& leader_list : leadership_list) {
716 if(ability.teacher_loc == leader_list.teacher_loc) {
717 leading_playable =
true;
722 for(
const unit_ability& helper_list : resistance_list) {
723 if(ability.teacher_loc == helper_list.teacher_loc) {
724 helping_playable =
true;
730 assert(leader.
valid());
731 leader->set_facing(ability.teacher_loc.get_relative_dir(
a));
733 att->get_location(), damage, hit_type, weapon, secondary_attack, swing) && leading_playable){
737 def->get_location(), damage, hit_type, weapon, secondary_attack, swing) && helping_playable){
741 att->get_location(), damage,
true,
"", {0,0,0},
742 hit_type, weapon, secondary_attack, swing);
748 int damage_left = damage;
749 bool extra_hit_sounds_played =
false;
750 while(damage_left > 0 && !animator.
would_end()) {
751 if(!extra_hit_sounds_played && extra_hit_sounds !=
nullptr) {
752 for (std::string hit_sound : *extra_hit_sounds) {
755 extra_hit_sounds_played =
true;
759 if(step_left < 1) step_left = 1;
760 int removed_hp = damage_left/step_left ;
761 if(removed_hp < 1) removed_hp = 1;
763 damage_left -= removed_hp;
768 def->anim_comp().start_animation(animator.
get_end_time(), defender_anim,
true);
770 def->set_hitpoints(def_hitpoints);
785 assert(leader != units.
end());
786 leader->anim_comp().set_standing();
797 assert(helper != units.
end());
798 helper->anim_comp().set_standing();
806 if(do_not_show_anims(disp) || (disp->
fogged(loc) && disp->
fogged(leader_loc))) {
815 const bool unit_visible = u->is_visible_to_team(viewing_team,
false);
818 const bool leader_visible = (leader != disp->
get_units().
end()) && leader->is_visible_to_team(viewing_team,
false);
824 u->set_hidden(
false);
828 if (leader_visible && unit_visible) {
830 }
else if (leader_visible) {
832 }
else if (unit_visible) {
839 if (leader_visible) {
852 const std::string & extra_text)
856 const bool some_healer_is_unfogged =
857 (healers.end() != std::find_if_not(healers.begin(), healers.end(),
858 [&](
unit*
h) { return disp->fogged(h->get_location()); }));
860 if(do_not_show_anims(disp) || (disp->
fogged(healed_loc) && !some_healer_is_unfogged)) {
869 for (
unit *
h : healers) {
870 h->set_facing(
h->get_location().get_relative_dir(healed_loc));
871 animator.
add_animation(
h->shared_from_this(),
"healing",
h->get_location(),
872 healed_loc, healing);
876 animator.
add_animation(healed.shared_from_this(),
"poisoned", healed_loc,
878 number_and_text(-healing, extra_text),
880 }
else if ( healing > 0 ) {
881 animator.
add_animation(healed.shared_from_this(),
"healed", healed_loc,
883 number_and_text(healing, extra_text),
886 animator.
add_animation(healed.shared_from_this(),
"healed", healed_loc,
888 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
Abstract class for exposing game data that doesn't depend on the GUI, however which for historical re...
const team & get_team(int side) const
This getter takes a 1-based side number, not a 0-based team number.
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
int viewing_side() const
The 1-based equivalent of the 0-based viewing_team() function.
const unit_map & get_units() const
const display_context & get_disp_context() 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.
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()
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)
void wait_until(int animation_time) const
int 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})
int get_animation_time_potential() const
A class to encapsulate the steps of drawing a unit's move.
int wait_until_
The animation potential to wait until.
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.
unit_ptr shown_unit_
The unit to be (re-)shown after an animation finishes.
void finish(unit_ptr u, map_location::DIRECTION dir=map_location::NDIRECTIONS)
Finishes the display of movement for the supplied unit.
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.
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
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 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.
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'.
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.