From 332a0f4d69643442ed6da29a05ce5b07003bcc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= Date: Sun, 5 Jan 2025 13:16:59 -0500 Subject: [PATCH 1/5] Added dynamic interface option --- .../dialog/dialog_interface_settings.cpp | 28 ++++--- src/fheroes2/game/game_campaign.cpp | 4 +- src/fheroes2/game/game_startgame.cpp | 11 ++- src/fheroes2/gui/ui_tool.cpp | 16 ++-- src/fheroes2/gui/ui_tool.h | 9 ++- src/fheroes2/system/settings.cpp | 81 +++++++++++++++---- src/fheroes2/system/settings.h | 12 ++- 7 files changed, 118 insertions(+), 43 deletions(-) diff --git a/src/fheroes2/dialog/dialog_interface_settings.cpp b/src/fheroes2/dialog/dialog_interface_settings.cpp index 95a913b18d0..0a1ef017dc0 100644 --- a/src/fheroes2/dialog/dialog_interface_settings.cpp +++ b/src/fheroes2/dialog/dialog_interface_settings.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2023 - 2024 * + * Copyright (C) 2023 - 2025 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -63,18 +63,28 @@ namespace void drawInterfaceType( const fheroes2::Rect & optionRoi ) { const Settings & conf = Settings::Get(); - const bool isEvilInterface = conf.isEvilInterfaceEnabled(); - const fheroes2::Sprite & interfaceThemeIcon = fheroes2::AGG::GetICN( ICN::SPANEL, isEvilInterface ? 17 : 16 ); + const InterfaceType interfaceType = conf.getInterfaceType(); + const fheroes2::Sprite * interfaceThemeIcon; std::string value; - if ( isEvilInterface ) { - value = _( "Evil" ); - } - else { + switch ( interfaceType ) { + case DYNAMIC: + interfaceThemeIcon = &fheroes2::AGG::GetICN( ICN::SPANEL, 15 ); + value = _( "Dynamic" ); + break; + case GOOD: + interfaceThemeIcon = &fheroes2::AGG::GetICN( ICN::SPANEL, 16 ); value = _( "Good" ); + break; + case EVIL: + interfaceThemeIcon = &fheroes2::AGG::GetICN( ICN::SPANEL, 17 ); + value = _( "Evil" ); + break; + default: + assert( 0 ); } - fheroes2::drawOption( optionRoi, interfaceThemeIcon, _( "Interface Type" ), std::move( value ), fheroes2::UiOptionTextWidth::TWO_ELEMENTS_ROW ); + fheroes2::drawOption( optionRoi, *interfaceThemeIcon, _( "Interface Type" ), std::move( value ), fheroes2::UiOptionTextWidth::TWO_ELEMENTS_ROW ); } void drawInterfacePresence( const fheroes2::Rect & optionRoi ) @@ -287,7 +297,7 @@ namespace fheroes2 windowType = showConfigurationWindow( saveConfiguration ); break; case SelectedWindow::InterfaceType: - conf.setEvilInterface( !conf.isEvilInterfaceEnabled() ); + conf.setInterfaceType( static_cast( ( conf.getInterfaceType() + 1 ) % ( InterfaceType::DYNAMIC + 1 ) ) ); updateUI(); saveConfiguration = true; diff --git a/src/fheroes2/game/game_campaign.cpp b/src/fheroes2/game/game_campaign.cpp index 7952a104bce..3ca488de0b9 100644 --- a/src/fheroes2/game/game_campaign.cpp +++ b/src/fheroes2/game/game_campaign.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2020 - 2024 * + * Copyright (C) 2020 - 2025 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -1307,7 +1307,7 @@ fheroes2::GameMode Game::SelectCampaignScenario( const fheroes2::GameMode prevMo const std::vector & scenarios = campaignData.getAllScenarios(); const Campaign::ScenarioData & scenario = scenarios[currentScenarioInfoId.scenarioId]; - const fheroes2::GameInterfaceTypeRestorer gameInterfaceRestorer( chosenCampaignID != Campaign::ROLAND_CAMPAIGN ); + const fheroes2::GameInterfaceTypeRestorer gameInterfaceRestorer( chosenCampaignID == Campaign::ROLAND_CAMPAIGN ? InterfaceType::GOOD : InterfaceType::EVIL ); if ( !allowToRestart ) { playCurrentScenarioVideo(); diff --git a/src/fheroes2/game/game_startgame.cpp b/src/fheroes2/game/game_startgame.cpp index 0f992f8e941..3434ba42dd8 100644 --- a/src/fheroes2/game/game_startgame.cpp +++ b/src/fheroes2/game/game_startgame.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2009 by Andrey Afletdinov * @@ -784,6 +784,13 @@ fheroes2::GameMode Interface::AdventureMap::StartGame() // Reset environment sounds and music theme at the beginning of the human turn AudioManager::ResetAudio(); + conf.SetCurrentColor( playerColor ); + if ( conf.getInterfaceType() == InterfaceType::DYNAMIC ) { + reset(); + redraw( Interface::REDRAW_RADAR ); + redraw( Interface::REDRAW_ALL & ( ~Interface::REDRAW_RADAR ) ); + } + if ( isHotSeatGame ) { _iconsPanel.hideIcons( ICON_ANY ); _statusPanel.Reset(); @@ -804,8 +811,6 @@ fheroes2::GameMode Interface::AdventureMap::StartGame() Game::DialogPlayers( playerColor, "", _( "%{color} player's turn." ) ); } - conf.SetCurrentColor( playerColor ); - kingdom.ActionBeforeTurn(); _iconsPanel.showIcons( ICON_ANY ); diff --git a/src/fheroes2/gui/ui_tool.cpp b/src/fheroes2/gui/ui_tool.cpp index e038207b088..c75f0a482e6 100644 --- a/src/fheroes2/gui/ui_tool.cpp +++ b/src/fheroes2/gui/ui_tool.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2020 - 2024 * + * Copyright (C) 2020 - 2025 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -296,19 +296,19 @@ namespace fheroes2 Display::instance().changePalette( palette ); } - GameInterfaceTypeRestorer::GameInterfaceTypeRestorer( const bool isEvilInterface_ ) - : isEvilInterface( isEvilInterface_ ) - , isOriginalEvilInterface( Settings::Get().isEvilInterfaceEnabled() ) + GameInterfaceTypeRestorer::GameInterfaceTypeRestorer( const InterfaceType interfaceType_ ) + : interfaceType( interfaceType_ ) + , originalInterfaceType( Settings::Get().getInterfaceType() ) { - if ( isEvilInterface != isOriginalEvilInterface ) { - Settings::Get().setEvilInterface( isEvilInterface ); + if ( interfaceType != originalInterfaceType ) { + Settings::Get().setInterfaceType( interfaceType_ ); } } GameInterfaceTypeRestorer::~GameInterfaceTypeRestorer() { - if ( isEvilInterface != isOriginalEvilInterface ) { - Settings::Get().setEvilInterface( isOriginalEvilInterface ); + if ( interfaceType != originalInterfaceType ) { + Settings::Get().setInterfaceType( originalInterfaceType ); } } diff --git a/src/fheroes2/gui/ui_tool.h b/src/fheroes2/gui/ui_tool.h index 86fa78f31a0..63fe2c74e11 100644 --- a/src/fheroes2/gui/ui_tool.h +++ b/src/fheroes2/gui/ui_tool.h @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2020 - 2024 * + * Copyright (C) 2020 - 2025 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -31,6 +31,7 @@ #include "image.h" #include "math_base.h" +#include "settings.h" #include "timing.h" #include "ui_base.h" #include "ui_text.h" @@ -174,7 +175,7 @@ namespace fheroes2 struct GameInterfaceTypeRestorer { GameInterfaceTypeRestorer() = delete; - explicit GameInterfaceTypeRestorer( const bool isEvilInterface_ ); + explicit GameInterfaceTypeRestorer( const InterfaceType interfaceType_ ); GameInterfaceTypeRestorer( const GameInterfaceTypeRestorer & ) = delete; @@ -182,8 +183,8 @@ namespace fheroes2 GameInterfaceTypeRestorer & operator=( const GameInterfaceTypeRestorer & ) = delete; - const bool isEvilInterface; - const bool isOriginalEvilInterface; + const InterfaceType interfaceType; + const InterfaceType originalInterfaceType; }; // Fade display image colors to grayscale part of default game palette. diff --git a/src/fheroes2/system/settings.cpp b/src/fheroes2/system/settings.cpp index 20d5e9636ed..dd8664c8aec 100644 --- a/src/fheroes2/system/settings.cpp +++ b/src/fheroes2/system/settings.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2009 by Andrey Afletdinov * @@ -36,6 +36,7 @@ #include "game.h" #include "game_io.h" #include "logging.h" +#include "race.h" #include "render_processor.h" #include "save_format_version.h" #include "screen.h" @@ -235,8 +236,17 @@ bool Settings::Read( const std::string & filePath ) setBattleShowTurnOrder( config.StrParams( "battle turn order" ) == "on" ); } - if ( config.Exists( "use evil interface" ) ) { - setEvilInterface( config.StrParams( "use evil interface" ) == "on" ); + if ( config.Exists( "interface type" ) ) { + std::string interfaceType = config.StrParams( "interface type" ); + if ( interfaceType == "Good" ) { + setInterfaceType( InterfaceType::GOOD ); + } + else if ( interfaceType == "Evil" ) { + setInterfaceType( InterfaceType::EVIL ); + } + else { + setInterfaceType( InterfaceType::DYNAMIC ); + } } if ( config.Exists( "hide interface" ) ) { @@ -432,8 +442,20 @@ std::string Settings::String() const os << std::endl << "# show turn order during battle: on/off" << std::endl; os << "battle turn order = " << ( _gameOptions.Modes( GAME_BATTLE_SHOW_TURN_ORDER ) ? "on" : "off" ) << std::endl; - os << std::endl << "# use evil interface style: on/off" << std::endl; - os << "use evil interface = " << ( _gameOptions.Modes( GAME_EVIL_INTERFACE ) ? "on" : "off" ) << std::endl; + os << std::endl << "# interface type (Good/Evil/Dynamic)" << std::endl; + switch ( _interfaceType ) { + case GOOD: + os << "interface type = Good" << std::endl; + break; + case EVIL: + os << "interface type = Evil" << std::endl; + break; + case DYNAMIC: + os << "interface type = Dynamic" << std::endl; + break; + default: + assert( 0 ); + } os << std::endl << "# hide interface elements on the adventure map: on/off" << std::endl; os << "hide interface = " << ( _gameOptions.Modes( GAME_HIDE_INTERFACE ) ? "on" : "off" ) << std::endl; @@ -816,16 +838,6 @@ void Settings::setHideInterface( const bool enable ) } } -void Settings::setEvilInterface( const bool enable ) -{ - if ( enable ) { - _gameOptions.SetModes( GAME_EVIL_INTERFACE ); - } - else { - _gameOptions.ResetModes( GAME_EVIL_INTERFACE ); - } -} - void Settings::setScreenScalingTypeNearest( const bool enable ) { if ( enable ) { @@ -883,9 +895,46 @@ bool Settings::isHideInterfaceEnabled() const return _gameOptions.Modes( GAME_HIDE_INTERFACE ); } +void Settings::setInterfaceType( InterfaceType type ) +{ + assert( type >= InterfaceType::GOOD && type <= InterfaceType::DYNAMIC ); + _interfaceType = type; +} + +InterfaceType Settings::getInterfaceType() const +{ + return _interfaceType; +} + bool Settings::isEvilInterfaceEnabled() const { - return _gameOptions.Modes( GAME_EVIL_INTERFACE ); + switch ( _interfaceType ) { + case InterfaceType::GOOD: + return false; + case InterfaceType::EVIL: + return true; + case InterfaceType::DYNAMIC: { + Player * player = Settings::Get().GetPlayers().GetCurrent(); + if ( !player ) + return false; + + if ( player->isControlHuman() ) { + const int race = player->GetRace(); + return race == Race::WRLK || race == Race::NECR || race == Race::BARB; + } + + // Keep the UI of the last player during the AI turn + for ( auto iter = Settings::Get().GetPlayers().rbegin(); iter < Settings::Get().GetPlayers().rend(); ++iter ) { + if ( *iter && ( *iter )->isControlHuman() ) { + const int race = ( *iter )->GetRace(); + return race == Race::WRLK || race == Race::NECR || race == Race::BARB; + } + } + return false; + } + default: + assert( 0 ); + } } bool Settings::isEditorAnimationEnabled() const diff --git a/src/fheroes2/system/settings.h b/src/fheroes2/system/settings.h index ff303388889..72ebd70137b 100644 --- a/src/fheroes2/system/settings.h +++ b/src/fheroes2/system/settings.h @@ -64,6 +64,13 @@ enum class ZoomLevel : uint8_t ZoomLevel3 = 3, // Max zoom, but should only exists for debug builds }; +enum InterfaceType : uint8_t +{ + GOOD = 0, + EVIL = 1, + DYNAMIC = 2, +}; + class Settings { public: @@ -191,6 +198,9 @@ class Settings bool isHideInterfaceEnabled() const; bool isEvilInterfaceEnabled() const; + void setInterfaceType( InterfaceType type ); + InterfaceType getInterfaceType() const; + bool isEditorAnimationEnabled() const; bool isEditorPassabilityEnabled() const; @@ -252,7 +262,6 @@ class Settings void setAutoSaveAtBeginningOfTurn( const bool enable ); void setBattleDamageInfo( const bool enable ); void setHideInterface( const bool enable ); - void setEvilInterface( const bool enable ); void setScreenScalingTypeNearest( const bool enable ); void SetSoundVolume( int v ); @@ -379,6 +388,7 @@ class Settings int ai_speed; int scroll_speed; int battle_speed; + InterfaceType _interfaceType; int game_type; ZoomLevel _viewWorldZoomLevel{ ZoomLevel::ZoomLevel1 }; From 7775059cc47946c97e9085ef2a73fdb1ffafe052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= Date: Sun, 5 Jan 2025 13:26:19 -0500 Subject: [PATCH 2/5] Clang-tidy --- src/fheroes2/system/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fheroes2/system/settings.cpp b/src/fheroes2/system/settings.cpp index dd8664c8aec..ba426680faa 100644 --- a/src/fheroes2/system/settings.cpp +++ b/src/fheroes2/system/settings.cpp @@ -237,7 +237,7 @@ bool Settings::Read( const std::string & filePath ) } if ( config.Exists( "interface type" ) ) { - std::string interfaceType = config.StrParams( "interface type" ); + const std::string interfaceType = config.StrParams( "interface type" ); if ( interfaceType == "Good" ) { setInterfaceType( InterfaceType::GOOD ); } From 09756de0c90b0298f1fe6ec32b65f47809d719d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= Date: Sun, 5 Jan 2025 13:33:08 -0500 Subject: [PATCH 3/5] IWYU + compilation issues --- src/fheroes2/dialog/dialog_interface_settings.cpp | 2 ++ src/fheroes2/gui/ui_tool.h | 3 ++- src/fheroes2/system/settings.cpp | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/fheroes2/dialog/dialog_interface_settings.cpp b/src/fheroes2/dialog/dialog_interface_settings.cpp index 0a1ef017dc0..fc2cfa564fe 100644 --- a/src/fheroes2/dialog/dialog_interface_settings.cpp +++ b/src/fheroes2/dialog/dialog_interface_settings.cpp @@ -81,6 +81,8 @@ namespace value = _( "Evil" ); break; default: + interfaceThemeIcon = &fheroes2::AGG::GetICN( ICN::SPANEL, 15 ); + value = _( "Dynamic" ); assert( 0 ); } diff --git a/src/fheroes2/gui/ui_tool.h b/src/fheroes2/gui/ui_tool.h index 63fe2c74e11..dba3df1dc08 100644 --- a/src/fheroes2/gui/ui_tool.h +++ b/src/fheroes2/gui/ui_tool.h @@ -31,11 +31,12 @@ #include "image.h" #include "math_base.h" -#include "settings.h" #include "timing.h" #include "ui_base.h" #include "ui_text.h" +enum InterfaceType : uint8_t; + namespace fheroes2 { class MovableSprite : public Sprite diff --git a/src/fheroes2/system/settings.cpp b/src/fheroes2/system/settings.cpp index ba426680faa..32d43d85731 100644 --- a/src/fheroes2/system/settings.cpp +++ b/src/fheroes2/system/settings.cpp @@ -22,6 +22,7 @@ ***************************************************************************/ #include +#include #include #include #include @@ -930,11 +931,13 @@ bool Settings::isEvilInterfaceEnabled() const return race == Race::WRLK || race == Race::NECR || race == Race::BARB; } } - return false; + break; } default: assert( 0 ); } + + return false; } bool Settings::isEditorAnimationEnabled() const From 751df9533fb22123f940135ad6135ee7e48a1ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= Date: Sun, 5 Jan 2025 13:50:52 -0500 Subject: [PATCH 4/5] Code review --- src/fheroes2/kingdom/race.cpp | 21 +++++++++++++++++++++ src/fheroes2/kingdom/race.h | 1 + src/fheroes2/system/settings.cpp | 6 ++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/fheroes2/kingdom/race.cpp b/src/fheroes2/kingdom/race.cpp index 6b6c8c407f7..f76be8ec4ff 100644 --- a/src/fheroes2/kingdom/race.cpp +++ b/src/fheroes2/kingdom/race.cpp @@ -126,6 +126,27 @@ bool Race::isMagicalRace( const int race ) return false; } +bool Race::isEvilRace( const int race ) +{ + switch ( race ) { + case BARB: + case WRLK: + case NECR: + return true; + case KNGT: + case SORC: + case WZRD: + case MULT: + case RAND: + return false; + default: + assert( 0 ); + break; + } + + return false; +} + uint8_t Race::IndexToRace( const int index ) { switch ( index ) { diff --git a/src/fheroes2/kingdom/race.h b/src/fheroes2/kingdom/race.h index 7aeedb064e7..b427d05eacf 100644 --- a/src/fheroes2/kingdom/race.h +++ b/src/fheroes2/kingdom/race.h @@ -53,4 +53,5 @@ namespace Race int getPreviousRace( const int race ); bool isMagicalRace( const int race ); + bool isEvilRace( const int race ); } diff --git a/src/fheroes2/system/settings.cpp b/src/fheroes2/system/settings.cpp index 32d43d85731..4cb2b092fb8 100644 --- a/src/fheroes2/system/settings.cpp +++ b/src/fheroes2/system/settings.cpp @@ -920,15 +920,13 @@ bool Settings::isEvilInterfaceEnabled() const return false; if ( player->isControlHuman() ) { - const int race = player->GetRace(); - return race == Race::WRLK || race == Race::NECR || race == Race::BARB; + return Race::isEvilRace( player->GetRace() ); } // Keep the UI of the last player during the AI turn for ( auto iter = Settings::Get().GetPlayers().rbegin(); iter < Settings::Get().GetPlayers().rend(); ++iter ) { if ( *iter && ( *iter )->isControlHuman() ) { - const int race = ( *iter )->GetRace(); - return race == Race::WRLK || race == Race::NECR || race == Race::BARB; + return Race::isEvilRace( ( *iter )->GetRace() ); } } break; From 3e1b60c9ab79c8d4489ffaeea0f6a51635b64534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= Date: Sun, 5 Jan 2025 13:59:12 -0500 Subject: [PATCH 5/5] Copyright --- src/fheroes2/kingdom/race.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fheroes2/kingdom/race.cpp b/src/fheroes2/kingdom/race.cpp index f76be8ec4ff..dba03127d2b 100644 --- a/src/fheroes2/kingdom/race.cpp +++ b/src/fheroes2/kingdom/race.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2009 by Andrey Afletdinov *