Highlight reachable hexes instead of darkening unreachable hexes (#9292)

This commit is contained in:
Descacharrado 2024-10-18 05:23:53 +02:00 committed by GitHub
parent 38a6508cf4
commit 52e132648d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 123 additions and 23 deletions

View file

@ -0,0 +1,2 @@
### User interface
* Hovering over units and selecting units now highlights reachable hexes instead of obscuring unreachable ones.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

View file

@ -85,7 +85,6 @@
mouseover="misc/hover-hex.png"
selected=""
editor_brush="editor/brush.png"
unreachable="terrain/darken.png"
linger="terrain/darken-linger.png"
observer="misc/eye.png"
@ -122,6 +121,7 @@
fog_prefix="terrain/fog/fog"
shroud_prefix="terrain/void/void"
reach_map_prefix="terrain/reachmap/reach"
{core/team-colors.cfg}
[/game_config]

View file

@ -42,6 +42,7 @@
{SIMPLE_KEY footprint_teleport_exit string}
{SIMPLE_KEY fog_prefix string}
{SIMPLE_KEY shroud_prefix string}
{SIMPLE_KEY reach_map_prefix string}
{SIMPLE_KEY show_ally_orb bool}
{SIMPLE_KEY show_disengaged_orb bool}
{SIMPLE_KEY show_enemy_orb bool}

View file

@ -67,7 +67,7 @@
("type_arcane" "type_cold" "type_fire" "type_impact" "type_pierce" "type_blade" "range_ranged" "range_melee" "village_name_swamp" "village_name_road" "village_name_mountain_anonymous" "village_name_mountain" "village_name_hill" "village_name_forest" "village_name_grassland" "village_name_river_bridge" "village_name_river" "village_name_lake" "village_name" "swamp_name" "mountain_name" "lake_name" "forest_name" "river_name" "road_name" "bridge_name" "liminal_description" "chaotic_description" "neutral_description" "lawful_description" "NIGHTMARE" "HARD" "NORMAL" "EASY" "type_electrical" "range_very_long"))
("game_config"
("images" "server")
("shroud_prefix" "fog_prefix" "blue_white_scale_text" "blue_white_scale" "hex_brightening" "default_terrain" "village_support" "xp_bar_scaling" "village_income" "unreachable_image" "unmoved_ball_image" "tod_bright_image" "title_music" "title" "tip_x" "tip_width" "tip_padding" "terrain_mask_image" "rest_heal_amount" "red_green_scale_text" "red_green_scale" "recall_cost" "poison_amount" "partmoved_ball_image" "observer_image" "moved_ball_image" "logo_y" "logo_x" "logo" "lobby_refresh" "lobby_music" "level_image" "kill_experience" "icon" "hp_bar_scaling" "grid_image" "footprint_teleport_exit" "footprint_teleport_enter" "footprint_prefix" "flag_rgb" "flag_image" "flag_icon_image" "energy_image" "enemy_ball_image" "ellipsis_image" "default_victory_music" "default_defeat_music" "cross_image" "buttons_padding" "buttons_y" "buttons_x" "base_income" "ally_ball_image" "_server" "_color_range" "_color_palette"))
("shroud_prefix" "fog_prefix" "reach_map_prefix" "blue_white_scale_text" "blue_white_scale" "hex_brightening" "default_terrain" "village_support" "xp_bar_scaling" "village_income" "unreachable_image" "unmoved_ball_image" "tod_bright_image" "title_music" "title" "tip_x" "tip_width" "tip_padding" "terrain_mask_image" "rest_heal_amount" "red_green_scale_text" "red_green_scale" "recall_cost" "poison_amount" "partmoved_ball_image" "observer_image" "moved_ball_image" "logo_y" "logo_x" "logo" "lobby_refresh" "lobby_music" "level_image" "kill_experience" "icon" "hp_bar_scaling" "grid_image" "footprint_teleport_exit" "footprint_teleport_enter" "footprint_prefix" "flag_rgb" "flag_image" "flag_icon_image" "energy_image" "enemy_ball_image" "ellipsis_image" "default_victory_music" "default_defeat_music" "cross_image" "buttons_padding" "buttons_y" "buttons_x" "base_income" "ally_ball_image" "_server" "_color_range" "_color_palette"))
("images" nil
("missing" "ellipsis" "level" "tod_dark" "tod_bright" "observer" "linger" "unreachable" "editor_brush" "selected" "mouseover" "grid_bottom" "grid_top" "terrain_mask" "flag_icon" "flag" "energy" "moved_orb_color" "partmoved_orb_color" "ally_orb_color" "unmoved_orb_color" "enemy_orb_color" "orb" "game_title_background" "game_title"))
("server" nil

View file

@ -850,6 +850,11 @@ gui::button::TYPE string_to_button_type(const std::string& type)
return gui::button::TYPE_PRESS;
}
}
} // namespace
namespace display_direction
{
// named namespace called in game_display.cpp
const std::string& get_direction(std::size_t n)
{
@ -857,7 +862,7 @@ const std::string& get_direction(std::size_t n)
static const std::array dirs{"-n"s, "-ne"s, "-se"s, "-s"s, "-sw"s, "-nw"s};
return dirs[n >= dirs.size() ? 0 : n];
}
} // namespace
} // namespace display_direction
void display::create_buttons()
{
@ -968,6 +973,7 @@ void display::unhide_buttons()
std::vector<texture> display::get_fog_shroud_images(const map_location& loc, image::TYPE image_type)
{
using namespace display_direction;
std::vector<std::string> names;
const auto adjacent = get_adjacent_tiles(loc);
@ -3302,7 +3308,7 @@ void display::process_reachmap_changes()
for (const auto& hex : get_visible_hexes()) {
reach_map::iterator reach = full.find(hex);
if (reach == full.end()) {
if (reach != full.end()) {
// Location needs to be darkened or brightened
invalidate(hex);
} else if (reach->second != 1) {
@ -3311,18 +3317,10 @@ void display::process_reachmap_changes()
}
}
} else if (!reach_map_.empty()) {
// Invalidate only changes
// Invalidate new and old reach
reach_map::iterator reach, reach_old;
for (reach = reach_map_.begin(); reach != reach_map_.end(); ++reach) {
reach_old = reach_map_old_.find(reach->first);
if (reach_old == reach_map_old_.end()) {
invalidate(reach->first);
} else {
if (reach_old->second != reach->second) {
invalidate(reach->first);
}
reach_map_old_.erase(reach_old);
}
invalidate(reach->first);
}
for (reach_old = reach_map_old_.begin(); reach_old != reach_map_old_.end(); ++reach_old) {
invalidate(reach_old->first);

View file

@ -73,6 +73,14 @@ namespace wb {
#include <memory>
#include <vector>
namespace display_direction {
/**
* @note needs to be defined after includes
* as it uses std::string
*/
const std::string& get_direction(std::size_t n);
}
struct submerge_data
{
rect unsub_src;

View file

@ -52,7 +52,7 @@ const int gold_carryover_percentage = 80;
unsigned int tile_size = 72;
std::string default_terrain;
std::string shroud_prefix, fog_prefix;
std::string shroud_prefix, fog_prefix, reach_map_prefix;
std::vector<unsigned int> zoom_levels {36, 72, 144};
@ -194,7 +194,6 @@ std::string
mouseover,
selected,
editor_brush,
unreachable,
linger,
// GUI elements
observer,
@ -350,7 +349,6 @@ void load_config(const config &v)
mouseover = i["mouseover"].str();
selected = i["selected"].str();
editor_brush = i["editor_brush"].str();
unreachable = i["unreachable"].str();
linger = i["linger"].str();
observer = i["observer"].str();
@ -371,6 +369,7 @@ void load_config(const config &v)
shroud_prefix = v["shroud_prefix"].str();
fog_prefix = v["fog_prefix"].str();
reach_map_prefix = v["reach_map_prefix"].str();
add_color_info(game_config_view::wrap(v), true);

View file

@ -121,7 +121,6 @@ namespace game_config
mouseover,
selected,
editor_brush,
unreachable,
linger,
// GUI elements
observer,
@ -141,7 +140,7 @@ namespace game_config
} //images
extern std::string shroud_prefix, fog_prefix;
extern std::string shroud_prefix, fog_prefix, reach_map_prefix;
extern double hp_bar_scaling, xp_bar_scaling;

View file

@ -271,10 +271,12 @@ void game_display::draw_hex(const map_location& loc)
// Draw reach_map information.
// We remove the reachability mask of the unit that we want to attack.
if(!is_shrouded && !reach_map_.empty() && reach_map_.find(loc) == reach_map_.end() && loc != attack_indicator_dst_) {
static const image::locator unreachable(game_config::images::unreachable);
drawing_buffer_add(drawing_layer::reachmap, loc,
[tex = image::get_texture(unreachable, image::HEXED)](const rect& dest) { draw::blit(tex, dest); });
if(!is_shrouded && !reach_map_.empty() && reach_map_.find(loc) != reach_map_.end() && loc != attack_indicator_dst_) {
drawing_buffer_add(drawing_layer::fog_shroud, loc, [images = get_reachmap_images(loc)](const rect& dest) {
for(const texture& t : images) {
draw::blit(t, dest);
}
});
}
if(std::shared_ptr<wb::manager> w = wb_.lock()) {
@ -657,3 +659,92 @@ display::overlay_map& game_display::get_overlays()
{
return overlay_map_;
}
std::vector<texture> game_display::get_reachmap_images(const map_location& loc) const
{
// Use get_direction() from display.cpp namespace display_direction
using namespace display_direction;
std::vector<std::string> names;
const auto adjacent = get_adjacent_tiles(loc);
enum visibility { REACH = 0, CLEAR = 1 };
std::array<visibility, 6> tiles;
const std::string* image_prefix_ = &game_config::reach_map_prefix;
DBG_DP << "Loaded image prefix: " << game_config::reach_map_prefix;
for(int i = 0; i < 6; ++i) {
if(reach_map_.find(adjacent[i]) != reach_map_.end()) {
DBG_DP << "Adjacent " << std::to_string(i) << " to tile " << loc << " is REACHABLE";
tiles[i] = REACH;
} else {
DBG_DP << "Adjacent " << std::to_string(i) << " to tile " << loc << " is NOT REACHABLE";
tiles[i] = CLEAR;
}
}
// Find out if location is in the inner part of reachmap (surrounded by reach)
int s;
for(s = 0; s != 6; ++s) {
if(tiles[s] != REACH) {
break;
}
}
if(s == 6) {
// Completely surrounded by reach. This may have a special graphic.
DBG_DP << "Tried completely surrounding";
std::string name = *image_prefix_ + "-all.png";
if(image::exists(name)) {
names.push_back(std::move(name));
}
}
else {
// else push the background image, as the rest of the graphics are meant to have it
names.push_back(*image_prefix_ + ".png");
}
// Find all the directions overlap occurs from
for(int i = 0, cap1 = 0; cap1 != 6; ++cap1) {
DBG_DP << "Testing " << get_direction(i);
if(tiles[i] != REACH) {
DBG_DP << "Direction " << get_direction(i) << " points to an unreachable hex";
std::ostringstream stream;
std::string name;
stream << *image_prefix_;
for(int cap2 = 0; tiles[i] != REACH && cap2 != 6; i = (i + 1) % 6, ++cap2) {
stream << get_direction(i);
if(!image::exists(stream.str() + ".png")) {
DBG_DP << "Image does not exist: " << stream.str() + ".png on " << loc;
// If we don't have any surface at all,
// then move onto the next overlapped area
if(name.empty()) {
i = (i + 1) % 6;
}
break;
} else {
name = stream.str();
}
}
DBG_DP << "Tried loading image: " << stream.str() + ".png on " << loc;
if(!name.empty()) {
names.push_back(name + ".png");
}
} else {
i = (i + 1) % 6;
}
}
// now get the textures
std::vector<texture> res;
for(const std::string& name : names) {
if(texture tex = image::get_texture(name, image::HEXED)) {
res.push_back(std::move(tex));
}
}
return res;
}

View file

@ -172,6 +172,8 @@ protected:
std::set<map_location> units_that_can_reach_goal_;
std::vector<texture> get_reachmap_images(const map_location& loc) const;
public:
/** Set the attack direction indicator. */
void set_attack_indicator(const map_location& src, const map_location& dst);