The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
game_display.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
3 by David White <dave@whitevine.net>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16/**
17 * @file
18 * During a game, show map & info-panels at top+right.
19 */
20
21#include "game_display.hpp"
22
23#include <cstdint>
24#include <utility>
25
26
27#include "cursor.hpp"
29#include "fake_unit_manager.hpp"
30#include "floating_label.hpp"
31#include "game_board.hpp"
32#include "picture.hpp"
34#include "log.hpp"
35#include "map/map.hpp"
37#include "reports.hpp"
38#include "resources.hpp"
39#include "tod_manager.hpp"
40#include "color.hpp"
41#include "synced_context.hpp"
42#include "units/unit.hpp"
43#include "units/drawer.hpp"
44#include "units/types.hpp"
45#include "utils/general.hpp"
47#include "overlay.hpp"
48#include "draw.hpp"
49
50static lg::log_domain log_display("display");
51#define ERR_DP LOG_STREAM(err, log_display)
52#define LOG_DP LOG_STREAM(info, log_display)
53#define DBG_DP LOG_STREAM(debug, log_display)
54
55static lg::log_domain log_engine("engine");
56#define ERR_NG LOG_STREAM(err, log_engine)
57
58
60 std::weak_ptr<wb::manager> wb,
61 reports& reports_object,
62 const std::string& theme_id,
63 const config& level)
64 : display(&board, std::move(wb), reports_object, theme_id, level)
65 , overlay_map_()
66 , attack_indicator_src_()
67 , attack_indicator_dst_()
68 , route_()
69 , displayedUnitHex_()
70 , first_turn_(true)
71 , in_game_(false)
72 , chat_man_(new display_chat_manager(*this))
73 , mode_(RUNNING)
74 , needs_rebuild_(false)
75 , flash_fade_route_()
76 , flash_fade_route_start_time_()
77 , flash_fade_route_active_(false)
78{
79}
80
82{
84 return;
85 }
86
87 auto now = std::chrono::steady_clock::now();
88 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - flash_fade_route_start_time_);
89
90 // Clean expired footpath
91 if(elapsed >= FLASH_FADE_ROUTE_TOTAL_DURATION) {
92 for(const auto& step : flash_fade_route_.steps) {
93 invalidate(step);
94 }
95
99 return;
100 }
101
102 // Trigger redraw of active path
103 for(const auto& step : flash_fade_route_.steps) {
104 invalidate(step);
105 }
106}
107
109{
110 // Clear existing flash fading footprints from the screen
112 for(const auto& step : flash_fade_route_.steps) {
113 invalidate(step);
114 }
115 }
116
117 // Reset the fading route data
118 flash_fade_route_.steps = remaining_route.steps;
119 flash_fade_route_.marks = remaining_route.marks;
120
121 // Start the animation cycle
122 if(!flash_fade_route_.steps.empty()) {
124 flash_fade_route_start_time_ = std::chrono::steady_clock::now();
125
126 // Trigger a redraw for all hexes in the new route
127 for(const auto& step : flash_fade_route_.steps) {
128 invalidate(step);
129 }
130 }
131}
132
134{
135 try {
136 chat_man_->prune_chat_messages(true);
137 } catch(...) {
138 DBG_DP << "Caught exception in game_display destructor: " << utils::get_unknown_exception_type();
139 }
140}
141
143{
144 if(!first_turn_) {
147
148 if(old_tod.image_mask != tod.image_mask) {
149 fade_tod_mask(old_tod.image_mask, tod.image_mask);
150 }
151 }
152
153 first_turn_ = false;
154
155 update_tod();
156}
157
159{
160 if(hex.valid() && fogged(hex)) {
161 return;
162 }
164
165 display_unit_hex(hex);
166}
167
169{
170 wb::future_map_if future(!synced_context::is_synced()); /**< Lasts for whole method. */
171
173 if (u) {
174 displayedUnitHex_ = hex;
176 } else {
178 if (u) {
179 // mouse moved from unit hex to non-unit hex
180 if (context().units().count(selectedHex_)) {
183 }
184 }
185 }
186
189}
190
191
193{
194 if (!hex.valid())
195 return;
196
197 wb::future_map_if future(!synced_context::is_synced()); /**< Lasts for whole method. */
198
200 if (u) {
201 displayedUnitHex_ = hex;
203 }
204}
205
213
214void game_display::scroll_to_leader(int side, SCROLL_TYPE scroll_type,bool force)
215{
217
218 if(leader.valid() && leader->is_visible_to_team(viewing_team(), false)) {
219 scroll_to_tile(leader->get_location(), scroll_type, true, force);
220 }
221}
222
224{
226
227 if (std::shared_ptr<wb::manager> w = wb_.lock()) {
228 w->pre_draw();
230 }
232 /**
233 * @todo FIXME: must modify changed, but best to do it at the
234 * floating_label level
235 */
236 chat_man_->prune_chat_messages();
237}
238
239
241{
243
244 if (std::shared_ptr<wb::manager> w = wb_.lock()) {
245 w->post_draw();
246 }
247}
248
250{
252 if (fake_unit_man_->empty()) {
253 return;
254 }
255 unit_drawer drawer = unit_drawer(*this);
256
257 for(const unit* temp_unit : *fake_unit_man_) {
258 const map_location& loc = temp_unit->get_location();
260 drawer.redraw_unit(*temp_unit);
261 }
262 }
263}
264
265namespace
266{
267const image::locator mouseover_normal_top
268 {"misc/hover-hex-top.png", "~RC(magenta>gold)"};
269const image::locator mouseover_normal_bot
270 {"misc/hover-hex-bottom.png", "~RC(magenta>gold)"};
271
272const image::locator mouseover_enemy_top
273 {"misc/hover-hex-enemy-top.png", "~RC(magenta>red)"};
274const image::locator mouseover_enemy_bot
275 {"misc/hover-hex-enemy-bottom.png", "~RC(magenta>red)"};
276
277const image::locator mouseover_self_top
278 {"misc/hover-hex-top.png", "~RC(magenta>green)"};
279const image::locator mouseover_self_bot
280 {"misc/hover-hex-bottom.png", "~RC(magenta>green)"};
281
282const image::locator mouseover_ally_top
283 {"misc/hover-hex-top.png", "~RC(magenta>lightblue)"};
284const image::locator mouseover_ally_bot
285 {"misc/hover-hex-bottom.png", "~RC(magenta>lightblue)"};
286
287/**
288 * Function to return 2 half-hex footsteps images for the given location.
289 * Only loc is on the current route set by set_route.
290 */
291std::vector<texture> footsteps_images(const map_location& loc, const pathfind::marked_route& route, const display_context* dc)
292{
293 std::vector<texture> res;
294
295 if (route.steps.size() < 2) {
296 return res; // no real "route"
297 }
298
299 std::vector<map_location>::const_iterator i =
300 std::find(route.steps.begin(),route.steps.end(),loc);
301
302 if( i == route.steps.end()) {
303 return res; // not on the route
304 }
305
306 // Determine which set of footprint images the unit uses
307 std::string footprints;
308 int move_cost = 1;
309 const unit_map::const_iterator u = dc->units().find(route.steps.front());
310 if(u != dc->units().end()) {
311 move_cost = u->movement_cost(dc->map().get_terrain(loc));
312 footprints = u->type().footprints();
313
314 // Fall back to the unit's race, which a [unit] may have overridden
315 if(footprints.empty()) {
316 footprints = u->race()->footprints();
317 }
318 }
319
320 if(footprints.empty()) {
321 footprints = "default";
322 }
323 const std::string foot_speed_prefix = "footsteps/" + footprints + "/";
324
325 // Custom colour per movement-cost step: no tint, then brown-orange, then strong red at 3+.
326 std::string color_mod;
327 if(move_cost == 2) {
328 color_mod = "~CS(-10,-70,-200)";
329 } else if(move_cost >= 3) {
330 color_mod = "~CS(0,-255,-255)";
331 }
332
333 texture teleport;
334
335 // We draw 2 half-hex (with possibly different directions),
336 // but skip the first for the first step.
337 const int first_half = (i == route.steps.begin()) ? 1 : 0;
338 // and the second for the last step
339 const int second_half = (i+1 == route.steps.end()) ? 0 : 1;
340
341 for (int h = first_half; h <= second_half; ++h) {
342 const std::string sense( h==0 ? "-in" : "-out" );
343
344 if (!tiles_adjacent(*(i+(h-1)), *(i+h))) {
345 std::string teleport_image =
347 teleport = image::get_texture(teleport_image, image::HEXED);
348 continue;
349 }
350
351 // In function of the half, use the incoming or outgoing direction
352 map_location::direction dir = (i+(h-1))->get_relative_dir(*(i+h));
353
354 std::string rotate;
356 // No image, take the opposite direction and do a 180 rotation
357 dir = i->get_opposite_direction(dir);
358 rotate = "~FL(horiz)~FL(vert)";
359 }
360
361 const std::string image = foot_speed_prefix + "footprint"
362 + sense + "-" + i->write_direction(dir)
363 + ".png" + rotate + color_mod;
364
365 res.push_back(image::get_texture(image, image::HEXED));
366 }
367
368 // we draw teleport image (if any) in last
369 if (teleport != nullptr) res.push_back(teleport);
370
371 return res;
372}
373
374struct flash_fade_step_renderer
375{
376 std::vector<texture> images;
377 std::chrono::steady_clock::time_point start_time;
378
379 void operator()(const rect& dest) const {
380 auto now = std::chrono::steady_clock::now();
381 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
382
384 // PHASE 1: White Flash (Additive)
385 float intensity = 1.0f - (static_cast<float>(elapsed.count()) /
387 uint8_t flash_val = static_cast<uint8_t>(intensity * 255);
388
389 for(texture t : images) {
390 draw::blit(t, dest); // Base
391
392 t.set_blend_mode(SDL_BLENDMODE_ADD);
393 t.set_alpha_mod(flash_val);
394 draw::blit(t, dest); // Additive pass
395 draw::blit(t, dest); // Additive pass
396
397 t.set_blend_mode(SDL_BLENDMODE_BLEND);
398 t.set_alpha_mod(255);
399 }
400 }
402 // PHASE 2: Alpha Fade
403 auto fade_elapsed = elapsed - game_display::FLASH_FADE_ROUTE_FLASH_DURATION;
404 float progress = static_cast<float>(fade_elapsed.count()) /
406
407 uint8_t alpha = static_cast<uint8_t>((1.0f - progress) * 255);
408
409 for(texture t : images) {
410 t.set_alpha_mod(alpha);
411 draw::blit(t, dest);
412 t.set_alpha_mod(255);
413 }
414 }
415 }
416};
417
418} //anonymous namespace
419
421{
422 const bool on_map = context().map().on_board(loc);
423 const bool is_shrouded = shrouded(loc);
424
426
427 if(cursor::get() == cursor::WAIT) {
428 // Interaction is disabled, so we don't need anything else
429 return;
430 }
431
432 if(on_map && loc == mouseoverHex_ && !map_screenshot_) {
435 if(u != nullptr) {
436 hex_top_layer = drawing_layer::mouseover_top;
437 }
438
439 const image::locator* mo_top_path;
440 const image::locator* mo_bot_path;
441
442 if(u == nullptr) {
443 mo_top_path = &mouseover_normal_top;
444 mo_bot_path = &mouseover_normal_bot;
445 } else if(viewing_team().is_enemy(u->side())) {
446 mo_top_path = &mouseover_enemy_top;
447 mo_bot_path = &mouseover_enemy_bot;
448 } else if(viewing_team().side() == u->side()) {
449 mo_top_path = &mouseover_self_top;
450 mo_bot_path = &mouseover_self_bot;
451 } else {
452 mo_top_path = &mouseover_ally_top;
453 mo_bot_path = &mouseover_ally_bot;
454 }
455
456 drawing_buffer_add(hex_top_layer, loc,
457 [tex = image::get_texture(*mo_top_path, image::HEXED)](const rect& dest) { draw::blit(tex, dest); });
458
460 [tex = image::get_texture(*mo_bot_path, image::HEXED)](const rect& dest) { draw::blit(tex, dest); });
461 }
462
463 // Draw reach_map information.
464 bool reachable = reach_map_.find(loc) != reach_map_.end();
465 // Darken unreachable
466 // We remove the reachability mask of the unit that we want to attack.
467 if(!is_shrouded && !reach_map_.empty() && !reachable && loc != attack_indicator_dst_) {
468 std::string darken_suffix = prefs::get().reach_map_darken_tex() ? "" : "~WIPE_ALPHA()";
469
471 uint8_t darken_opacity = prefs::get().reach_map_darken_opacity() * (255.0/100.0);
472 darken_tex.set_alpha_mod(darken_opacity);
473
475 [darken_tex](const rect& dest) {
476 draw::blit(darken_tex, dest);
477 });
478 }
479 // Highlight reachable
480 if(!is_shrouded && !reach_map_.empty() && reachable) {
481 // draw the reachmap tint below units and high terrain graphics
482 std::string color = prefs::get().reach_map_color();
483 texture tint_tex = image::get_texture(game_config::reach_map_prefix + ".png~RC(magenta>"+color+")", image::HEXED);
484 uint8_t tint_opacity = prefs::get().reach_map_tint_opacity() * (255.0/100.0);
485 tint_tex.set_alpha_mod(tint_opacity);
486
488 draw::blit(tint_tex, dest);
489 });
490
491 // We remove the reachmap border mask of the hovered hex to avoid weird interactions with other visual objects.
492 if(loc != mouseoverHex_) {
493 // draw the highlight borders on top of units and terrain
495 for(const texture& t : images) {
496 draw::blit(t, dest);
497 }
498 });
499 }
500 }
501
502 // Check if Whiteboard is active to avoid overlapping path visualizations.
503 if(std::shared_ptr<wb::manager> w = wb_.lock()) {
504 w->draw_hex(loc);
505
506 if(!(w->is_active() && w->has_temp_move())) {
507
508 // Draw standard footsteps for the current turn's route.
509 std::vector<texture> footstepImages = footsteps_images(loc, route_, dc_);
510 if(!footstepImages.empty()) {
511 drawing_buffer_add(drawing_layer::footsteps, loc, [images = std::move(footstepImages)](const rect& dest) {
512 for(const texture& t : images) {
513 draw::blit(t, dest);
514 }
515 });
516 }
517
518 // Draw the flash fade effect for queued (future turn) moves.
520 std::vector<texture> images = footsteps_images(loc, flash_fade_route_, dc_);
521 if(!images.empty()) {
523 flash_fade_step_renderer{ std::move(images), flash_fade_route_start_time_ });
524 }
525 }
526 }
527 }
528
529 // Draw the attack direction indicator
530 if(on_map && loc == attack_indicator_src_) {
532 [tex = image::get_texture("misc/attack-indicator-src-" + attack_indicator_direction() + ".png", image::HEXED)](const rect& dest)
533 { draw::blit(tex, dest); }
534 );
535 } else if(on_map && loc == attack_indicator_dst_) {
537 [tex = image::get_texture("misc/attack-indicator-dst-" + attack_indicator_direction() + ".png", image::HEXED)](const rect& dest)
538 { draw::blit(tex, dest); }
539 );
540 }
541
542 // Linger overlay unconditionally otherwise it might give glitches
543 // so it's drawn over the shroud and fog.
544 if(mode_ != RUNNING) {
545 static const image::locator linger(game_config::images::linger);
547 [tex = image::get_texture(linger, image::TOD_COLORED)](const rect& dest) { draw::blit(tex, dest); });
548 }
549
550 if(on_map && loc == selectedHex_ && !game_config::images::selected.empty()) {
551 static const image::locator selected(game_config::images::selected);
553 [tex = image::get_texture(selected, image::HEXED)](const rect& dest) { draw::blit(tex, dest); });
554 }
555
556 // Show def% and turn to reach info
557 if(!is_shrouded && on_map) {
559 }
560}
561
566
571
573{
575
576 // We need teams for the reports below
577 if(context().teams().empty()) {
578 return;
579 }
580
581 refresh_report("report_clock");
582 refresh_report("report_battery");
583 refresh_report("report_countdown");
584
586 {
587 wb::future_map future; // start planned unit map scope
588
589 // We display the unit the mouse is over if it is over a unit,
590 // otherwise we display the unit that is selected.
591 for (const std::string &name : reports_object_->report_list()) {
592 refresh_report(name);
593 }
594 invalidateGameStatus_ = false;
595 }
596}
597
598
600{
601 if(mode != mode_) {
602 mode_ = mode;
604 }
605}
606
608{
609 // Search if there is a mark here
610 pathfind::marked_route::mark_map::iterator w = route_.marks.find(loc);
611
612 std::shared_ptr<wb::manager> wb = wb_.lock();
613
614 // Don't use empty route or the first step (the unit will be there)
615 if(w != route_.marks.end()
616 && !route_.steps.empty() && route_.steps.front() != loc) {
617 const unit_map::const_iterator un =
618 (wb && wb->get_temp_move_unit().valid()) ?
619 wb->get_temp_move_unit() : context().units().find(route_.steps.front());
620 if(un != context().units().end()) {
621 // Display the def% of this terrain
622 int def = 100 - un->defense_modifier(context().map().get_terrain(loc), loc);
623 std::stringstream def_text;
624 def_text << def << "%";
625
626 color_t color = game_config::red_to_green(def, false);
627
628 // simple mark (no turn point) use smaller font
629 int def_font = w->second.turns > 0 ? 18 : 16;
630 draw_text_in_hex(loc, drawing_layer::move_info, def_text.str(), def_font, color);
631
633 [inv = w->second.invisible, zoc = w->second.zoc, cap = w->second.capture](const rect& dest) {
634 if(inv) {
635 draw::blit(image::get_texture(image::locator{"misc/hidden.png"}, image::HEXED), dest);
636 }
637
638 if(zoc) {
639 draw::blit(image::get_texture(image::locator{"misc/zoc.png"}, image::HEXED), dest);
640 }
641
642 if(cap) {
643 draw::blit(image::get_texture(image::locator{"misc/capture.png"}, image::HEXED), dest);
644 }
645 });
646
647 //we display turn info only if different from a simple last "1"
648 if (w->second.turns > 1 || (w->second.turns == 1 && loc != route_.steps.back())) {
649 std::stringstream turns_text;
650 turns_text << w->second.turns;
651 draw_text_in_hex(loc, drawing_layer::move_info, turns_text.str(), 17, font::NORMAL_COLOR, 0.5,0.8);
652 }
653
654 // The hex is full now, so skip the "show enemy moves"
655 return;
656 }
657 }
658 // When out-of-turn, it's still interesting to check out the terrain defs of the selected unit
659 else if (selectedHex_.valid() && loc == mouseoverHex_)
660 {
661 const unit_map::const_iterator selectedUnit = resources::gameboard->find_visible_unit(selectedHex_,viewing_team());
662 const unit_map::const_iterator mouseoveredUnit = resources::gameboard->find_visible_unit(mouseoverHex_,viewing_team());
663 if(selectedUnit != context().units().end() && mouseoveredUnit == context().units().end()) {
664 // Display the def% of this terrain
665 int def = 100 - selectedUnit->defense_modifier(context().map().get_terrain(loc), loc);
666 std::stringstream def_text;
667 def_text << def << "%";
668
669 color_t color = game_config::red_to_green(def, false);
670
671 // use small font
672 int def_font = 16;
673 draw_text_in_hex(loc, drawing_layer::move_info, def_text.str(), def_font, color);
674 }
675 }
676
677 if (!reach_map_.empty()) {
678 reach_map::iterator reach = reach_map_.find(loc);
679 if (reach != reach_map_.end() && reach->second > 1) {
680 const std::string num = std::to_string(reach->second);
681 draw_text_in_hex(loc, drawing_layer::move_info, num, 16, font::YELLOW_COLOR);
682 }
683 }
684}
685
687{
689 highlight_another_reach(paths_list);
690}
691
693 const map_location& goal)
694{
695 // Fold endpoints of routes into reachability map.
696 for (const pathfind::paths::step &dest : paths_list.destinations) {
697 reach_map_[dest.curr]++;
698 }
699 reach_map_changed_ = true;
700
701 if(goal != map_location::null_location() && paths_list.destinations.contains(goal)) {
702 const auto& path_to_goal = paths_list.destinations.get_path(paths_list.destinations.find(goal));
703 const map_location enemy_unit_location = path_to_goal[0];
704 units_that_can_reach_goal_.insert(enemy_unit_location);
705 }
706}
707
709{
711 if(!reach_map_.empty()) {
712 reach_map_.clear();
713 reach_map_changed_ = true;
714 return true;
715 } else {
716 return false;
717 }
718}
719
721{
722 for(const map_location& step : route_.steps) {
723 invalidate(step);
724 }
725}
726
728{
730
731 if(route != nullptr) {
732 route_ = *route;
733 } else {
734 route_.steps.clear();
735 route_.marks.clear();
736 }
737
739}
740
741void game_display::float_label(const map_location& loc, const std::string& text, const color_t& color)
742{
743 if(prefs::get().floating_labels() == false || fogged(loc)) {
744 return;
745 }
746
747 rect loc_rect = get_location_rect(loc);
748
749 using namespace std::chrono_literals;
750 const auto lifetime = 1s / turbo_speed();
751
752 // Base speed is 100 pixels per second, taken in milliseconds
753 const double pixels_per_millisecond = 0.1 * turbo_speed() * get_zoom_factor();
754
755 font::floating_label flabel(text);
757 flabel.set_color(color);
758 flabel.set_position(loc_rect.center().x, loc_rect.y); // middle of top edge
759 flabel.set_move(0, -pixels_per_millisecond); // moving up
760 flabel.set_lifetime(0ms, std::chrono::round<std::chrono::milliseconds>(lifetime));
762
764}
765
779
784
786{
787 in_game_ = true;
790}
791
793 if (b) {
794 needs_rebuild_ = true;
795 }
796}
797
799 if (needs_rebuild_) {
800 needs_rebuild_ = false;
803 rebuild_all();
804 return true;
805 }
806 return false;
807}
808
813
814std::vector<texture> game_display::get_reachmap_images(const map_location& loc) const
815{
816 std::vector<std::string> names;
817 const auto adjacent = get_adjacent_tiles(loc);
818
819 enum visibility { REACH = 0, ENEMY = 1, CLEAR = 2 };
820 std::array<visibility, 6> tiles;
821
822 for(int i = 0; i < 6; ++i) {
823 // look for units adjacent to loc
824 std::string test_location = std::to_string(adjacent[i].x) + "," + std::to_string(adjacent[i].y);
825 const unit *u = context().get_visible_unit(adjacent[i], viewing_team());
826 if(reach_map_.find(adjacent[i]) != reach_map_.end()) {
827 DBG_DP << test_location << " is REACHABLE";
828 tiles[i] = REACH;
829 }
830 /**
831 * Make sure there is a unit selected or displayed when drawing the reachmap with enemy detection.
832 * Enemy detection needs to be "disabled" when the reach_map_team_index_ failsafes to viewing_team_index.
833 */
835 DBG_DP << test_location << " is NOT REACHABLE";
836 tiles[i] = CLEAR;
837 }
838 // Grab the reachmap-context team index updated in "display::process_reachmap_changes()" and test for adjacent enemy units
840 DBG_DP << test_location << " has an attackable ENEMY";
841 tiles[i] = ENEMY;
842 } else {
843 DBG_DP << test_location << " is NOT REACHABLE";
844 tiles[i] = CLEAR;
845 }
846 }
847
848 // Find out if location is in the inner part of reachmap (surrounded by reach)
849 int s;
850 for(s = 0; s != 6; ++s) {
851 if(tiles[s] != REACH) {
852 break;
853 }
854 }
855
856 if(s == 6) {
857 // Completely surrounded by reach. This may have a special graphic.
858 DBG_DP << "Tried completely surrounding";
859 std::string name = game_config::reach_map_prefix + "-all.png";
860 if(image::exists(name)) {
861 names.push_back(std::move(name));
862 }
863 }
864
865 // Find all the directions overlap occurs from
866 for(int i = 0, cap1 = 0; cap1 != 6; ++cap1) {
867 if(tiles[i] != REACH) {
868 std::ostringstream stream;
869 std::string suffix;
870 std::string name;
872
873 std::string color = prefs::get().reach_map_color();
874 std::string enemy_color = prefs::get().reach_map_enemy_color();
875
876 if(tiles[i] == ENEMY) {
877 suffix = ".png~RC(magenta>"+enemy_color+")";
878 } else {
879 suffix = ".png~RC(magenta>"+color+")";
880 }
881
882 for(int cap2 = 0; tiles[i] != REACH && cap2 != 6; i = (i + 1) % 6, ++cap2) {
884 if(!image::exists(stream.str() + ".png")) {
885 DBG_DP << "Image does not exist: " << stream.str() + ".png on " << loc;
886 // If we don't have any surface at all,
887 // then move onto the next overlapped area
888 if(name.empty()) {
889 i = (i + 1) % 6;
890 }
891 break;
892 } else {
893 name = stream.str();
894 }
895 }
896
897 if(!name.empty()) {
898 names.push_back(name + suffix);
899 }
900 } else {
901 i = (i + 1) % 6;
902 }
903 }
904
905 // now get the textures
906 std::vector<texture> res;
907 uint8_t border_opacity = prefs::get().reach_map_border_opacity() * (255.0/100.0);
908
909 for(const std::string& name : names) {
910 DBG_DP << "Pushing: " << name;
911 if(texture tex = image::get_texture(name, image::HEXED)) {
912 tex.set_alpha_mod(border_opacity);
913 res.push_back(std::move(tex));
914 }
915 }
916
917 return res;
918}
static bool is_enemy(std::size_t side, std::size_t other_side)
map_location loc
Definition move.cpp:172
const std::vector< map_location > & route_
Definition move.cpp:386
double t
std::vector< std::string > names
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
Abstract class for exposing game data that doesn't depend on the GUI, however which for historical re...
virtual const gamemap & map() const =0
const unit * get_visible_unit(const map_location &loc, const team &current_team, bool see_all=false) 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.
Definition display.hpp:88
const team & viewing_team() const
Definition display.cpp:337
bool map_screenshot_
Used to indicate to drawing functions that we are doing a map screenshot.
Definition display.hpp:862
void draw_text_in_hex(const map_location &loc, const drawing_layer layer, const std::string &text, std::size_t font_size, color_t color, double x_in_hex=0.5, double y_in_hex=0.5)
Draw text on a hex.
Definition display.cpp:1358
std::size_t viewing_team_index_
Definition display.hpp:713
std::map< map_location, std::vector< overlay > > overlay_map
Definition display.hpp:884
map_location selectedHex_
Definition display.hpp:761
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition display.cpp:1465
bool unit_can_draw_here(const map_location &loc, const unit &unit) const
Returns true if there is no exclusive draw request for loc, or if there is, that it's for unit.
Definition display.cpp:381
virtual void render() override
Update offscreen render buffers.
Definition display.cpp:2251
void fade_tod_mask(const std::string &old, const std::string &new_)
ToD mask smooth fade.
Definition display.cpp:2046
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition display.cpp:2927
double turbo_speed() const
Definition display.cpp:1965
bool reach_map_changed_
Definition display.hpp:879
static double get_zoom_factor()
Returns the current zoom factor.
Definition display.hpp:262
void invalidate_game_status()
Function to invalidate the game status displayed on the sidebar.
Definition display.hpp:308
void rebuild_all()
Rebuild all dynamic terrain.
Definition display.cpp:428
virtual void layout() override
Finalize screen layout.
Definition display.cpp:2220
virtual void highlight_hex(map_location hex)
Definition display.cpp:1389
void update_tod(const time_of_day *tod_override=nullptr)
Applies r,g,b coloring to the map.
Definition display.cpp:387
void process_reachmap_changes()
Definition display.cpp:3098
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.
Definition display.cpp:1815
map_location mouseoverHex_
Definition display.hpp:762
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition display.cpp:669
void invalidate_all()
Function to invalidate all tiles.
Definition display.cpp:2920
void drawing_buffer_add(const drawing_layer layer, const map_location &loc, decltype(draw_helper::do_draw) draw_func)
Add an item to the drawing buffer.
Definition display.cpp:1241
std::size_t reach_map_team_index_
Definition display.hpp:881
rect get_location_rect(const map_location &loc) const
Returns the on-screen rect corresponding to a loc.
Definition display.cpp:685
std::set< map_location > invalidated_
Definition display.hpp:751
void create_buttons()
Definition display.cpp:831
bool invalidateGameStatus_
Definition display.hpp:739
virtual void draw_invalidated()
Only called when there's actual redrawing to do.
Definition display.cpp:2407
reports * reports_object_
Definition display.hpp:741
virtual void update() override
Update animations and internal state.
Definition display.cpp:2203
virtual void draw_hex(const map_location &loc)
Redraws a single gamemap location.
Definition display.cpp:2443
const std::unique_ptr< fake_unit_manager > fake_unit_man_
Definition display.hpp:732
const display_context * dc_
Definition display.hpp:670
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition display.cpp:664
bool dont_show_all_
Definition display.hpp:714
void refresh_report(const std::string &report_name, const config *new_cfg=nullptr)
Update the given report.
Definition display.cpp:2676
std::weak_ptr< wb::manager > wb_
Definition display.hpp:672
const display_context & context() const
Definition display.hpp:187
virtual void select_hex(map_location hex)
Definition display.cpp:1381
reach_map reach_map_
Definition display.hpp:877
void set_move(double xmove, double ymove)
void set_position(double xpos, double ypos)
void set_lifetime(const std::chrono::milliseconds &lifetime, const std::chrono::milliseconds &fadeout=std::chrono::milliseconds{100})
void set_color(const color_t &color)
void set_scroll_mode(LABEL_SCROLL_MODE scroll)
void set_font_size(int font_size)
Game board class.
unit_map::iterator find_visible_unit(const map_location &loc, const team &current_team, bool see_all=false)
team & get_team(int i)
virtual void draw_invalidated() override
Only called when there's actual redrawing to do.
void draw_movement_info(const map_location &loc)
Draws the movement info (turns available) for a given location.
void display_unit_hex(map_location hex)
Change the unit to be displayed in the sidebar.
void invalidate_unit_after_move(const map_location &src, const map_location &dst)
Same as invalidate_unit() if moving the displayed unit.
std::string attack_indicator_direction() const
Function to get attack direction suffix.
game_mode mode_
void flash_fade_route(const pathfind::marked_route &route)
Visualizes a path by flashing it white then fade out over 2 seconds.
virtual void highlight_hex(map_location hex) override
Function to highlight a location.
map_location displayedUnitHex_
void invalidate_route()
std::vector< texture > get_reachmap_images(const map_location &loc) const
void scroll_to_leader(int side, SCROLL_TYPE scroll_type=ONSCREEN, bool force=true)
Scrolls to the leader of a certain side.
static constexpr std::chrono::milliseconds FLASH_FADE_ROUTE_FLASH_DURATION
void set_game_mode(const game_mode mode)
virtual void draw_hex(const map_location &loc) override
Redraws a single gamemap location.
void set_attack_indicator(const map_location &src, const map_location &dst)
Set the attack direction indicator.
const std::unique_ptr< display_chat_manager > chat_man_
pathfind::marked_route route_
virtual void render() override
TLD render() override.
void set_route(const pathfind::marked_route *route)
Sets the route along which footsteps are drawn to show movement of a unit.
virtual overlay_map & get_overlays() override
Inherited from display.
static constexpr std::chrono::milliseconds FLASH_FADE_ROUTE_TOTAL_DURATION
void update_flash_fade_route()
static constexpr std::chrono::milliseconds FLASH_FADE_ROUTE_FADE_DURATION
bool flash_fade_route_active_
std::set< map_location > units_that_can_reach_goal_
void invalidate_unit()
Function to invalidate that unit status displayed on the sidebar.
virtual void select_hex(map_location hex) override
Function to display a location as selected.
pathfind::marked_route flash_fade_route_
void highlight_reach(const pathfind::paths &paths_list)
Sets the paths that are currently displayed as available for the unit to move along.
void new_turn()
Update lighting settings.
void clear_attack_indicator()
virtual const time_of_day & get_time_of_day(const map_location &loc) const override
void highlight_another_reach(const pathfind::paths &paths_list, const map_location &goal=map_location::null_location())
Add more paths to highlight.
map_location attack_indicator_dst_
game_mode
Sets the linger mode for the display.
@ RUNNING
no linger overlay, show fog and shroud.
std::chrono::steady_clock::time_point flash_fade_route_start_time_
bool unhighlight_reach()
Reset highlighting of paths.
void needs_rebuild(bool b)
Sets whether the screen (map visuals) needs to be rebuilt.
overlay_map overlay_map_
bool maybe_rebuild()
Rebuilds the screen if needs_rebuild(true) was previously called, and resets the flag.
virtual void layout() override
TLD layout() override.
virtual bool has_time_area() const override
game_display(game_board &board, std::weak_ptr< wb::manager > wb, reports &reports_object, const std::string &theme_id, const config &level)
virtual void update() override
TLD update() override.
map_location attack_indicator_src_
void float_label(const map_location &loc, const std::string &text, const color_t &color)
Function to float a label above a tile.
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition map.cpp:265
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition map.cpp:347
Generic locator abstracting the location of an image.
Definition picture.hpp:59
static prefs & get()
int reach_map_darken_opacity()
bool reach_map_darken_tex()
int reach_map_tint_opacity()
std::string reach_map_color()
std::string reach_map_enemy_color()
int reach_map_border_opacity()
const std::set< std::string > & report_list()
Definition reports.cpp:1917
static bool is_synced()
bool is_enemy(int n) const
Definition team.hpp:270
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition texture.hpp:33
void set_alpha_mod(uint8_t alpha)
Alpha modifier.
Definition texture.cpp:146
bool has_time_area() const
const time_of_day & get_time_of_day(int for_turn=0) const
Returns global time of day for the passed turn.
const time_of_day & get_previous_time_of_day() const
void redraw_unit(const unit &u) const
draw a unit.
Definition drawer.cpp:202
unit_iterator end()
Definition map.hpp:428
unit_iterator find(std::size_t id)
Definition map.cpp:302
unit_iterator find_leader(int side)
Definition map.cpp:320
This class represents a single unit of a specific type.
Definition unit.hpp:39
#define DBG_DP
Definition display.cpp:79
Drawing functions, for drawing things on the screen.
drawing_layer
@ linger_overlay
The overlay used for the linger mode.
@ reachmap_highlight
Overlay on reachable hexes.
@ footsteps
Footsteps showing path from unit to mouse.
@ attack_indicator
Layer which holds the attack indicator.
@ reachmap_border
Overlay border of reachable hexes.
@ reachmap_darken
Overlay on unreachable hexes.
@ mouseover_top
Top half of image following the mouse.
@ mouseover_bottom
Bottom half of image following the mouse.
@ move_info
Movement info (defense%, etc...)
@ selected_hex
Image on the selected unit.
static lg::log_domain log_engine("engine")
static lg::log_domain log_display("display")
bool incapacitated() const
Check if the unit has been petrified.
Definition unit.hpp:826
int side() const
The side this unit belongs to.
Definition unit.hpp:249
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.
Definition location.cpp:513
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition location.cpp:541
Standard logging facilities (interface).
bool is_shrouded(const display *disp, const map_location &loc)
Our definition of map labels being obscured is if the tile is obscured, or the tile below is obscured...
Definition label.cpp:33
CURSOR_TYPE get()
Definition cursor.cpp:185
@ WAIT
Definition cursor.hpp:28
void blit(const texture &tex, const ::rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition draw.cpp:409
const int SIZE_FLOAT_LABEL
Definition constants.cpp:32
const color_t YELLOW_COLOR
int add_floating_label(const floating_label &flabel)
add a label floating on the screen above everything else.
const color_t NORMAL_COLOR
@ ANCHOR_LABEL_MAP
std::string unreachable
std::string foot_teleport_enter
std::string foot_teleport_exit
std::string reach_map_prefix
color_t red_to_green(double val, bool for_text)
Return a color corresponding to the value val red for val=0.0 to green for val=100....
Functions to load and save images from/to disk.
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
Definition picture.cpp:855
@ HEXED
Standard hexagonal tile mask applied, removing portions that don't fit.
Definition picture.hpp:175
@ TOD_COLORED
Same as HEXED, but with Time of Day color tint applied.
Definition picture.hpp:177
texture get_texture(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image texture suitable for hardware-accelerated rendering.
Definition picture.cpp:955
Unit and team statistics.
::tod_manager * tod_manager
Definition resources.cpp:29
game_board * gameboard
Definition resources.cpp:20
STL namespace.
T end(const std::pair< T, T > &p)
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition general.hpp:88
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
Definition general.cpp:23
Definition display.hpp:45
int w
Definition pathfind.cpp:188
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition color.hpp:51
Encapsulates the map of the game.
Definition location.hpp:46
static std::string write_direction(direction dir)
Definition location.cpp:154
bool valid() const
Definition location.hpp:111
direction
Valid directions which can be moved in our hexagonal world.
Definition location.hpp:48
static const map_location & null_location()
Definition location.hpp:103
Structure which holds a single route and marks for special events.
Definition pathfind.hpp:142
std::vector< map_location > & steps
Definition pathfind.hpp:187
std::vector< map_location > get_path(const const_iterator &) const
Returns the path going from the source point (included) to the destination point j (excluded).
Definition pathfind.cpp:497
bool contains(const map_location &) const
Definition pathfind.cpp:514
const_iterator find(const map_location &) const
Definition pathfind.cpp:478
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Definition pathfind.hpp:73
dest_vect destinations
Definition pathfind.hpp:101
An abstract description of a rectangle with integer coordinates.
Definition rect.hpp:49
constexpr point center() const
The center point of the rectangle, accounting for origin.
Definition rect.hpp:106
Object which defines a time of day with associated bonuses, image, sounds etc.
std::string image_mask
The image that is to be laid over all images while this time of day lasts.
bool valid() const
Definition map.hpp:273
Applies the planned unit map for the duration of the struct's life.
Definition manager.hpp:253
static map_location::direction s
#define i
#define h
#define b