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.
 
unit_movement_animator(const unit_movement_animator &)=delete
 
fake_unit_ptr temp_unit_ptr_
 
std::chrono::milliseconds wait_until_
The animation potential to wait until.
 
~unit_movement_animator()
 
void replace_temporary(const unit_ptr &u)
Makes the temporary unit used by this match the supplied unit.
 
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 update_shown_unit()
Switches the display back to *shown_unit_ after animating.
 
unit_ptr shown_unit_
The unit to be (re-)shown after an animation finishes.
 
game_display *const disp_
 
void wait_for_anims()
Waits for the final animation of the most recent proceed_to() to finish.
 
const std::vector< map_location > & path_
 
void finish(const unit_ptr &u, map_location::direction dir=map_location::direction::indeterminate)
Finishes the display of movement for the supplied unit.
 
void start(const unit_ptr &u)
Initiates the display of movement for the supplied unit.
 
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.