From 48a72f90f7165fa350819fd71343b5a00423ddb5 Mon Sep 17 00:00:00 2001 From: Dydzio Date: Mon, 17 Jul 2023 23:25:16 +0200 Subject: [PATCH 1/3] Add option for persistent hero info window as in HD mod --- Mods/vcmi/config/vcmi/english.json | 2 + client/battle/BattleInterface.cpp | 7 ++ client/battle/BattleInterface.h | 1 + client/battle/BattleInterfaceClasses.cpp | 45 +++++++++-- client/battle/BattleInterfaceClasses.h | 15 +++- client/battle/BattleWindow.cpp | 80 +++++++++++++++++++ client/battle/BattleWindow.h | 9 +++ client/gui/Shortcut.h | 1 + client/gui/ShortcutHandler.cpp | 1 + client/windows/settings/BattleOptionsTab.cpp | 20 +++++ client/windows/settings/BattleOptionsTab.h | 1 + config/schemas/settings.json | 6 +- config/widgets/settings/battleOptionsTab.json | 8 ++ 13 files changed, 188 insertions(+), 8 deletions(-) diff --git a/Mods/vcmi/config/vcmi/english.json b/Mods/vcmi/config/vcmi/english.json index d2d264574..775d618ae 100644 --- a/Mods/vcmi/config/vcmi/english.json +++ b/Mods/vcmi/config/vcmi/english.json @@ -113,6 +113,8 @@ "vcmi.battleOptions.movementHighlightOnHover.help": "{Movement Highlight on Hover}\n\nHighlight unit's movement range when you hover over it.", "vcmi.battleOptions.rangeLimitHighlightOnHover.hover": "Show range limits for shooters", "vcmi.battleOptions.rangeLimitHighlightOnHover.help": "{Show range limits for shooters on Hover}\n\nShow shooter's range limits when you hover over it.", + "vcmi.battleOptions.showStickyHeroInfoWindows.hover": "Permanently show heroes statistics windows", + "vcmi.battleOptions.showStickyHeroInfoWindows.help": "{Permanently show heroes statistics windows}\n\nPermanently toggle on heroes statistics windows that show primary stats and spell points.", "vcmi.battleOptions.skipBattleIntroMusic.hover": "Skip Intro Music", "vcmi.battleOptions.skipBattleIntroMusic.help": "{Skip Intro Music}\n\nAllow actions during the intro music that plays at the beginning of each battle", "vcmi.battleWindow.pressKeyToSkipIntro" : "Press any key to start battle immediately", diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index 01de5edaa..42826a8ba 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -810,3 +810,10 @@ void BattleInterface::setBattleQueueVisibility(bool visible) if(visible) windowObject->showQueue(); } + +void BattleInterface::setStickyHeroWindowsVisibility(bool visible) +{ + windowObject->hideStickyHeroWindows(); + if(visible) + windowObject->showStickyHeroWindows(); +} diff --git a/client/battle/BattleInterface.h b/client/battle/BattleInterface.h index 475dda6dd..38d27466e 100644 --- a/client/battle/BattleInterface.h +++ b/client/battle/BattleInterface.h @@ -178,6 +178,7 @@ public: void tacticPhaseEnd(); void setBattleQueueVisibility(bool visible); + void setStickyHeroWindowsVisibility(bool visible); void executeStagedAnimations(); void executeAnimationStage( EAnimationEvents event); diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index cc54c36cb..68dbd9a3a 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -296,9 +296,20 @@ void BattleHero::heroLeftClicked() void BattleHero::heroRightClicked() { + if(settings["battle"]["stickyHeroInfoWindows"].Bool()) + return; + Point windowPosition; - windowPosition.x = (!defender) ? owner.fieldController->pos.left() + 1 : owner.fieldController->pos.right() - 79; - windowPosition.y = owner.fieldController->pos.y + 135; + if(GH.screenDimensions().x < 1000) + { + windowPosition.x = (!defender) ? owner.fieldController->pos.left() + 1 : owner.fieldController->pos.right() - 79; + windowPosition.y = owner.fieldController->pos.y + 135; + } + else + { + windowPosition.x = (!defender) ? owner.fieldController->pos.left() - 93 : owner.fieldController->pos.right() + 15; + windowPosition.y = owner.fieldController->pos.y; + } InfoAboutHero targetHero; if(owner.makingTurn() || settings["session"]["spectate"].Bool()) @@ -364,13 +375,19 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her addUsedEvents(TIME); } -HeroInfoWindow::HeroInfoWindow(const InfoAboutHero & hero, Point * position) - : CWindowObject(RCLICK_POPUP | SHADOW_DISABLED, "CHRPOP") +HeroInfoBasicPanel::HeroInfoBasicPanel(const InfoAboutHero & hero, Point * position, bool initializeBackground) + : CIntObject(0) { OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); if (position != nullptr) moveTo(*position); - background->colorize(hero.owner); //maybe add this functionality to base class? + + if(initializeBackground) + { + background = std::make_shared("CHRPOP"); + background->getSurface()->setBlitMode(EImageBlitMode::OPAQUE); + background->colorize(hero.owner); + } auto attack = hero.details->primskills[0]; auto defense = hero.details->primskills[1]; @@ -406,6 +423,24 @@ HeroInfoWindow::HeroInfoWindow(const InfoAboutHero & hero, Point * position) labels.push_back(std::make_shared(39, 186, EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, std::to_string(currentSpellPoints) + "/" + std::to_string(maxSpellPoints))); } +void HeroInfoBasicPanel::show(Canvas & to) +{ + showAll(to); + CIntObject::show(to); +} + +HeroInfoWindow::HeroInfoWindow(const InfoAboutHero & hero, Point * position) + : CWindowObject(RCLICK_POPUP | SHADOW_DISABLED, "CHRPOP") +{ + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + if (position != nullptr) + moveTo(*position); + + background->colorize(hero.owner); //maybe add this functionality to base class? + + content = std::make_shared(hero, nullptr, false); +} + BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface & _owner, bool allowReplay) : owner(_owner) { diff --git a/client/battle/BattleInterfaceClasses.h b/client/battle/BattleInterfaceClasses.h index 7a2ac574b..5f730d56e 100644 --- a/client/battle/BattleInterfaceClasses.h +++ b/client/battle/BattleInterfaceClasses.h @@ -127,11 +127,22 @@ public: BattleHero(const BattleInterface & owner, const CGHeroInstance * hero, bool defender); }; +class HeroInfoBasicPanel : public CIntObject //extracted from InfoWindow to fit better as non-popup embed element +{ +private: + std::shared_ptr background; + std::vector> labels; + std::vector> icons; +public: + HeroInfoBasicPanel(const InfoAboutHero & hero, Point * position, bool initializeBackground = true); + + void show(Canvas & to) override; +}; + class HeroInfoWindow : public CWindowObject { private: - std::vector> labels; - std::vector> icons; + std::shared_ptr content; public: HeroInfoWindow(const InfoAboutHero & hero, Point * position); }; diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index 26fc2c572..ea07ac257 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -67,6 +67,7 @@ BattleWindow::BattleWindow(BattleInterface & owner): addShortcut(EShortcut::BATTLE_SELECT_ACTION, std::bind(&BattleWindow::bSwitchActionf, this)); addShortcut(EShortcut::BATTLE_TOGGLE_QUEUE, [this](){ this->toggleQueueVisibility();}); + addShortcut(EShortcut::BATTLE_TOGGLE_HEROES_STATS, [this](){ this->toggleStickyHeroWindowsVisibility();}); addShortcut(EShortcut::BATTLE_USE_CREATURE_SPELL, [this](){ this->owner.actionsController->enterCreatureCastingMode(); }); addShortcut(EShortcut::GLOBAL_CANCEL, [this](){ this->owner.actionsController->endCastingSpell(); }); @@ -80,6 +81,7 @@ BattleWindow::BattleWindow(BattleInterface & owner): owner.fieldController->createHeroes(); createQueue(); + createStickyHeroInfoWindows(); if ( owner.tacticsMode ) tacticPhaseStarted(); @@ -116,6 +118,41 @@ void BattleWindow::createQueue() queue->disable(); } +void BattleWindow::createStickyHeroInfoWindows() +{ + OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; + + if(owner.defendingHeroInstance) + { + InfoAboutHero info; + info.initFromHero(owner.defendingHeroInstance, InfoAboutHero::EInfoLevel::INBATTLE); + Point position = (GH.screenDimensions().x >= 1000) + ? Point(pos.x + pos.w + 15, pos.y) + : Point(pos.x + pos.w -79, pos.y + 135); + defenderHeroWindow = std::make_shared(info, &position); + } + if(owner.attackingHeroInstance) + { + InfoAboutHero info; + info.initFromHero(owner.attackingHeroInstance, InfoAboutHero::EInfoLevel::INBATTLE); + Point position = (GH.screenDimensions().x >= 1000) + ? Point(pos.x - 93, pos.y) + : Point(pos.x + 1, pos.y + 135); + attackerHeroWindow = std::make_shared(info, &position); + } + + bool showInfoWindows = settings["battle"]["stickyHeroInfoWindows"].Bool(); + + if(!showInfoWindows) + { + if(attackerHeroWindow) + attackerHeroWindow->disable(); + + if(defenderHeroWindow) + defenderHeroWindow->disable(); + } +} + BattleWindow::~BattleWindow() { CPlayerInterface::battleInt = nullptr; @@ -170,6 +207,49 @@ void BattleWindow::showQueue() GH.windows().totalRedraw(); } +void BattleWindow::toggleStickyHeroWindowsVisibility() +{ + if(settings["battle"]["stickyHeroInfoWindows"].Bool()) + hideStickyHeroWindows(); + else + showStickyHeroWindows(); +} + +void BattleWindow::hideStickyHeroWindows() +{ + if(settings["battle"]["stickyHeroInfoWindows"].Bool() == false) + return; + + Settings showStickyHeroInfoWindows = settings.write["battle"]["stickyHeroInfoWindows"]; + showStickyHeroInfoWindows->Bool() = false; + + if(attackerHeroWindow) + attackerHeroWindow->disable(); + + if(defenderHeroWindow) + defenderHeroWindow->disable(); + + GH.windows().totalRedraw(); +} + +void BattleWindow::showStickyHeroWindows() +{ + if(settings["battle"]["stickyHeroInfoWindows"].Bool() == true) + return; + + Settings showStickyHeroInfoWIndows = settings.write["battle"]["stickyHeroInfoWindows"]; + showStickyHeroInfoWIndows->Bool() = true; + +// if(attackerHeroWindow) +// attackerHeroWindow->enable(); +// +// if(defenderHeroWindow) +// defenderHeroWindow->enable(); + + createStickyHeroInfoWindows(); + GH.windows().totalRedraw(); +} + void BattleWindow::updateQueue() { queue->update(); diff --git a/client/battle/BattleWindow.h b/client/battle/BattleWindow.h index 379b85e52..0b37f1e1e 100644 --- a/client/battle/BattleWindow.h +++ b/client/battle/BattleWindow.h @@ -24,6 +24,7 @@ class BattleInterface; class BattleConsole; class BattleRenderer; class StackQueue; +class HeroInfoBasicPanel; /// GUI object that handles functionality of panel at the bottom of combat screen class BattleWindow : public InterfaceObjectConfigurable @@ -32,6 +33,8 @@ class BattleWindow : public InterfaceObjectConfigurable std::shared_ptr queue; std::shared_ptr console; + std::shared_ptr attackerHeroWindow; + std::shared_ptr defenderHeroWindow; /// button press handling functions void bOptionsf(); @@ -60,6 +63,9 @@ class BattleWindow : public InterfaceObjectConfigurable void toggleQueueVisibility(); void createQueue(); + void toggleStickyHeroWindowsVisibility(); + void createStickyHeroInfoWindows(); + std::shared_ptr buildBattleConsole(const JsonNode &) const; public: @@ -73,6 +79,9 @@ public: void hideQueue(); void showQueue(); + void hideStickyHeroWindows(); + void showStickyHeroWindows(); + /// block all UI elements when player is not allowed to act, e.g. during enemy turn void blockUI(bool on); diff --git a/client/gui/Shortcut.h b/client/gui/Shortcut.h index 778bfaac9..9f4c19891 100644 --- a/client/gui/Shortcut.h +++ b/client/gui/Shortcut.h @@ -133,6 +133,7 @@ enum class EShortcut BATTLE_TACTICS_NEXT, BATTLE_TACTICS_END, BATTLE_SELECT_ACTION, // Alternative actions toggle + BATTLE_TOGGLE_HEROES_STATS, // Town screen TOWN_OPEN_TAVERN, diff --git a/client/gui/ShortcutHandler.cpp b/client/gui/ShortcutHandler.cpp index 039034085..a36a1ddbc 100644 --- a/client/gui/ShortcutHandler.cpp +++ b/client/gui/ShortcutHandler.cpp @@ -134,6 +134,7 @@ std::vector ShortcutHandler::translateKeycode(SDL_Keycode key) const {SDLK_RETURN, EShortcut::BATTLE_TACTICS_END }, {SDLK_KP_ENTER, EShortcut::BATTLE_TACTICS_END }, {SDLK_s, EShortcut::BATTLE_SELECT_ACTION }, + {SDLK_i, EShortcut::BATTLE_TOGGLE_HEROES_STATS}, {SDLK_t, EShortcut::TOWN_OPEN_TAVERN }, {SDLK_SPACE, EShortcut::TOWN_SWAP_ARMIES }, {SDLK_END, EShortcut::RECRUITMENT_MAX }, diff --git a/client/windows/settings/BattleOptionsTab.cpp b/client/windows/settings/BattleOptionsTab.cpp index 475fb604e..99f874a4e 100644 --- a/client/windows/settings/BattleOptionsTab.cpp +++ b/client/windows/settings/BattleOptionsTab.cpp @@ -60,6 +60,10 @@ BattleOptionsTab::BattleOptionsTab(BattleInterface * owner) { skipBattleIntroMusicChangedCallback(value); }); + addCallback("showStickyHeroWindowsChanged", [this, owner](bool value) + { + showStickyHeroWindowsChangedCallback(value, owner); + }); build(config); std::shared_ptr animationSpeedToggle = widget("animationSpeedPicker"); @@ -80,6 +84,9 @@ BattleOptionsTab::BattleOptionsTab(BattleInterface * owner) std::shared_ptr rangeLimitHighlightOnHoverCheckbox = widget("rangeLimitHighlightOnHoverCheckbox"); rangeLimitHighlightOnHoverCheckbox->setSelected(settings["battle"]["rangeLimitHighlightOnHover"].Bool()); + std::shared_ptr showStickyHeroInfoWindowsCheckbox = widget("showStickyHeroInfoWindowsCheckbox"); + showStickyHeroInfoWindowsCheckbox->setSelected(settings["battle"]["stickyHeroInfoWindows"].Bool()); + std::shared_ptr mouseShadowCheckbox = widget("mouseShadowCheckbox"); mouseShadowCheckbox->setSelected(settings["battle"]["mouseShadow"].Bool()); @@ -194,6 +201,19 @@ void BattleOptionsTab::showQueueChangedCallback(bool value, BattleInterface * pa } } +void BattleOptionsTab::showStickyHeroWindowsChangedCallback(bool value, BattleInterface * parentBattleInterface) +{ + if(!parentBattleInterface) + { + Settings showStickyWindows = settings.write["battle"]["stickyHeroInfoWindows"]; + showStickyWindows->Bool() = value; + } + else + { + parentBattleInterface->setStickyHeroWindowsVisibility(value); + } +} + void BattleOptionsTab::queueSizeChangedCallback(int value, BattleInterface * parentBattleInterface) { if (value == -1) diff --git a/client/windows/settings/BattleOptionsTab.h b/client/windows/settings/BattleOptionsTab.h index 5449f9f51..6a71d2e68 100644 --- a/client/windows/settings/BattleOptionsTab.h +++ b/client/windows/settings/BattleOptionsTab.h @@ -31,6 +31,7 @@ private: void showQueueChangedCallback(bool value, BattleInterface * parentBattleInterface); void queueSizeChangedCallback(int value, BattleInterface * parentBattleInterface); void skipBattleIntroMusicChangedCallback(bool value); + void showStickyHeroWindowsChangedCallback(bool value, BattleInterface * parentBattleInterface); public: BattleOptionsTab(BattleInterface * owner = nullptr); }; diff --git a/config/schemas/settings.json b/config/schemas/settings.json index a712c7f95..060107e61 100644 --- a/config/schemas/settings.json +++ b/config/schemas/settings.json @@ -238,7 +238,7 @@ "type" : "object", "additionalProperties" : false, "default" : {}, - "required" : [ "speedFactor", "mouseShadow", "cellBorders", "stackRange", "movementHighlightOnHover", "rangeLimitHighlightOnHover", "showQueue", "swipeAttackDistance", "queueSize" ], + "required" : [ "speedFactor", "mouseShadow", "cellBorders", "stackRange", "movementHighlightOnHover", "rangeLimitHighlightOnHover", "showQueue", "swipeAttackDistance", "queueSize", "stickyHeroInfoWindows" ], "properties" : { "speedFactor" : { "type" : "number", @@ -276,6 +276,10 @@ "type" : "string", "default" : "auto", "enum" : [ "auto", "small", "big" ] + }, + "stickyHeroInfoWindows" : { + "type" : "boolean", + "default" : true } } }, diff --git a/config/widgets/settings/battleOptionsTab.json b/config/widgets/settings/battleOptionsTab.json index a0ce1e424..0fde2a031 100644 --- a/config/widgets/settings/battleOptionsTab.json +++ b/config/widgets/settings/battleOptionsTab.json @@ -110,6 +110,9 @@ { "text": "vcmi.battleOptions.rangeLimitHighlightOnHover.hover", }, + { + "text": "vcmi.battleOptions.showStickyHeroInfoWindows.hover", + }, { "text": "core.genrltxt.406", }, @@ -144,6 +147,11 @@ "help": "vcmi.battleOptions.rangeLimitHighlightOnHover", "callback": "rangeLimitHighlightOnHoverChanged" }, + { + "name": "showStickyHeroInfoWindowsCheckbox", + "help": "vcmi.battleOptions.showStickyHeroInfoWindows", + "callback": "showStickyHeroWindowsChanged" + }, { "name": "mouseShadowCheckbox", "help": "core.help.429", From dea9c6327d49160885b012aab97e4132e1240eb2 Mon Sep 17 00:00:00 2001 From: Dydzio Date: Tue, 18 Jul 2023 15:15:38 +0200 Subject: [PATCH 2/3] Update english.json --- Mods/vcmi/config/vcmi/english.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mods/vcmi/config/vcmi/english.json b/Mods/vcmi/config/vcmi/english.json index 775d618ae..6522d9923 100644 --- a/Mods/vcmi/config/vcmi/english.json +++ b/Mods/vcmi/config/vcmi/english.json @@ -113,8 +113,8 @@ "vcmi.battleOptions.movementHighlightOnHover.help": "{Movement Highlight on Hover}\n\nHighlight unit's movement range when you hover over it.", "vcmi.battleOptions.rangeLimitHighlightOnHover.hover": "Show range limits for shooters", "vcmi.battleOptions.rangeLimitHighlightOnHover.help": "{Show range limits for shooters on Hover}\n\nShow shooter's range limits when you hover over it.", - "vcmi.battleOptions.showStickyHeroInfoWindows.hover": "Permanently show heroes statistics windows", - "vcmi.battleOptions.showStickyHeroInfoWindows.help": "{Permanently show heroes statistics windows}\n\nPermanently toggle on heroes statistics windows that show primary stats and spell points.", + "vcmi.battleOptions.showStickyHeroInfoWindows.hover": "Show heroes statistics windows", + "vcmi.battleOptions.showStickyHeroInfoWindows.help": "{Show heroes statistics windows}\n\nPermanently toggle on heroes statistics windows that show primary stats and spell points.", "vcmi.battleOptions.skipBattleIntroMusic.hover": "Skip Intro Music", "vcmi.battleOptions.skipBattleIntroMusic.help": "{Skip Intro Music}\n\nAllow actions during the intro music that plays at the beginning of each battle", "vcmi.battleWindow.pressKeyToSkipIntro" : "Press any key to start battle immediately", From f4f789804d9e4ed697a088665eaa75ce2f46e0af Mon Sep 17 00:00:00 2001 From: Dydzio Date: Tue, 18 Jul 2023 15:15:58 +0200 Subject: [PATCH 3/3] Update client/battle/BattleWindow.cpp Co-authored-by: Ivan Savenko --- client/battle/BattleWindow.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index ea07ac257..4fe763e04 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -240,11 +240,6 @@ void BattleWindow::showStickyHeroWindows() Settings showStickyHeroInfoWIndows = settings.write["battle"]["stickyHeroInfoWindows"]; showStickyHeroInfoWIndows->Bool() = true; -// if(attackerHeroWindow) -// attackerHeroWindow->enable(); -// -// if(defenderHeroWindow) -// defenderHeroWindow->enable(); createStickyHeroInfoWindows(); GH.windows().totalRedraw();