diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index 97c62659a..dcbf427a8 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -31,6 +31,7 @@ #include "../render/IFont.h" #include "../render/Graphics.h" #include "../widgets/Buttons.h" +#include "../widgets/CComponent.h" #include "../widgets/Images.h" #include "../widgets/Slider.h" #include "../widgets/TextControls.h" @@ -39,9 +40,11 @@ #include "../windows/CMessage.h" #include "../windows/CCreatureWindow.h" #include "../windows/CSpellWindow.h" +#include "../windows/InfoWindows.h" #include "../render/CAnimation.h" #include "../render/IRenderHandler.h" #include "../adventureMap/CInGameConsole.h" +#include "../eventsSDL/InputHandler.h" #include "../../CCallback.h" #include "../../lib/CStack.h" @@ -55,6 +58,8 @@ #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/networkPacks/PacksForClientBattle.h" #include "../../lib/TextOperations.h" +#include "../../lib/json/JsonUtils.h" + void BattleConsole::showAll(Canvas & to) { @@ -417,6 +422,79 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her addUsedEvents(TIME); } +QuickSpellPanel::QuickSpellPanel(BattleInterface & owner) + : CIntObject(0), owner(owner) +{ + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + + addUsedEvents(LCLICK | SHOW_POPUP | MOVE); + + pos = Rect(0, 0, 52, 600); + background = std::make_shared(ImagePath::builtin("DIBOXBCK"), pos); + rect = std::make_shared(Rect(0, 0, pos.w + 1, pos.h + 1), ColorRGBA(0, 0, 0, 0), ColorRGBA(241, 216, 120, 255)); + + create(); +} + +void QuickSpellPanel::create() +{ + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + + const JsonNode config = JsonUtils::assembleFromFiles("config/shortcutsConfig"); + + labels.clear(); + buttons.clear(); + buttonsDisabled.clear(); + + auto hero = owner.getBattle()->battleGetMyHero(); + if(!hero) + return; + + for(int i = 0; i < 12; i++) { + std::string spellIdentifier = persistentStorage["quickSpell"][std::to_string(i)].String(); + + SpellID id; + try + { + id = SpellID::decode(spellIdentifier); + } + catch(const IdentifierResolutionException& e) + { + id = SpellID::NONE; + } + + auto button = std::make_shared(Point(2, 7 + 50 * i), AnimationPath::builtin("spellint"), CButton::tooltip(), [this, id, hero](){ + if(id.hasValue() && id.toSpell()->canBeCast(owner.getBattle().get(), spells::Mode::HERO, hero)) + { + owner.castThisSpell(id); + } + }); + button->setOverlay(std::make_shared(AnimationPath::builtin("spellint"), !spellIdentifier.empty() ? id.num + 1 : 0)); + button->addPopupCallback([this, i, hero](){ + GH.input().hapticFeedback(); + GH.windows().createAndPushWindow(hero, owner.curInt.get(), true, [this, i](SpellID spell){ + Settings configID = persistentStorage.write["quickSpell"][std::to_string(i)]; + configID->String() = spell.toSpell()->identifier; + create(); + }); + }); + + if(!id.hasValue() || !id.toSpell()->canBeCast(owner.getBattle().get(), spells::Mode::HERO, hero)) + { + buttonsDisabled.push_back(std::make_shared(Rect(2, 7 + 50 * i, 48, 36), ColorRGBA(0, 0, 0, 172))); + } + labels.push_back(std::make_shared(7, 10 + 50 * i, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, config["keyboard"]["battleSpellShortcut" + std::to_string(i)].String())); + + buttons.push_back(button); + } +} + +void QuickSpellPanel::show(Canvas & to) +{ + showAll(to); + CIntObject::show(to); +} + HeroInfoBasicPanel::HeroInfoBasicPanel(const InfoAboutHero & hero, Point * position, bool initializeBackground) : CIntObject(0) { diff --git a/client/battle/BattleInterfaceClasses.h b/client/battle/BattleInterfaceClasses.h index c385db754..d40f04ea4 100644 --- a/client/battle/BattleInterfaceClasses.h +++ b/client/battle/BattleInterfaceClasses.h @@ -22,6 +22,7 @@ class CGHeroInstance; struct BattleResult; struct InfoAboutHero; class CStack; +class CPlayerBattleCallback; namespace battle { @@ -44,6 +45,7 @@ class TransparentFilledRectangle; class CPlayerInterface; class BattleRenderer; class VideoWidget; +class QuickSpellPanel; /// Class which shows the console at the bottom of the battle screen and manages the text of the console class BattleConsole : public CIntObject, public IStatusBar @@ -147,6 +149,26 @@ public: BattleHero(const BattleInterface & owner, const CGHeroInstance * hero, bool defender); }; +class QuickSpellPanel : public CIntObject +{ +private: + std::shared_ptr background; + std::shared_ptr rect; + std::vector> buttons; + std::vector> buttonsDisabled; + std::vector> labels; + + BattleInterface & owner; +public: + bool isEnabled; // isActive() is not working on multiple conditions, because of this we need a seperate flag + + QuickSpellPanel(BattleInterface & owner); + + void create(); + + void show(Canvas & to) override; +}; + class HeroInfoBasicPanel : public CIntObject //extracted from InfoWindow to fit better as non-popup embed element { private: diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index ecbc2af2f..0f90f357b 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -45,8 +45,8 @@ #include "../../lib/CPlayerState.h" #include "../windows/settings/SettingsMainWindow.h" -BattleWindow::BattleWindow(BattleInterface & owner): - owner(owner), +BattleWindow::BattleWindow(BattleInterface & Owner): + owner(Owner), lastAlternativeAction(PossiblePlayerBattleAction::INVALID) { OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; @@ -64,6 +64,20 @@ BattleWindow::BattleWindow(BattleInterface & owner): const JsonNode config(JsonPath::builtin("config/widgets/BattleWindow2.json")); + addShortcut(EShortcut::BATTLE_TOGGLE_QUICKSPELL, [this](){ this->toggleStickyQuickSpellVisibility();}); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_0, [this](){ useSpellIfPossible(0); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_1, [this](){ useSpellIfPossible(1); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_2, [this](){ useSpellIfPossible(2); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_3, [this](){ useSpellIfPossible(3); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_4, [this](){ useSpellIfPossible(4); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_5, [this](){ useSpellIfPossible(5); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_6, [this](){ useSpellIfPossible(6); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_7, [this](){ useSpellIfPossible(7); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_8, [this](){ useSpellIfPossible(8); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_9, [this](){ useSpellIfPossible(9); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_10, [this](){ useSpellIfPossible(10); }); + addShortcut(EShortcut::BATTLE_SPELL_SHORTCUT_11, [this](){ useSpellIfPossible(11); }); + addShortcut(EShortcut::GLOBAL_OPTIONS, std::bind(&BattleWindow::bOptionsf, this)); addShortcut(EShortcut::BATTLE_SURRENDER, std::bind(&BattleWindow::bSurrenderf, this)); addShortcut(EShortcut::BATTLE_RETREAT, std::bind(&BattleWindow::bFleef, this)); @@ -95,6 +109,7 @@ BattleWindow::BattleWindow(BattleInterface & owner): owner.fieldController->createHeroes(); createQueue(); + createQuickSpellWindow(); createStickyHeroInfoWindows(); createTimerInfoWindows(); @@ -164,10 +179,67 @@ void BattleWindow::createStickyHeroInfoWindows() setPositionInfoWindow(); } +void BattleWindow::createQuickSpellWindow() +{ + OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; + + quickSpellWindow = std::make_shared(owner); + quickSpellWindow->moveTo(Point(pos.x - 67, pos.y)); + + if(settings["battle"]["enableQuickSpellPanel"].Bool()) + showStickyQuickSpellWindow(); + else + hideStickyQuickSpellWindow(); +} + +void BattleWindow::toggleStickyQuickSpellVisibility() +{ + if(settings["battle"]["enableQuickSpellPanel"].Bool()) + hideStickyQuickSpellWindow(); + else + showStickyQuickSpellWindow(); +} + +void BattleWindow::hideStickyQuickSpellWindow() +{ + Settings showStickyQuickSpellWindow = settings.write["battle"]["enableQuickSpellPanel"]; + showStickyQuickSpellWindow->Bool() = false; + + quickSpellWindow->disable(); + quickSpellWindow->isEnabled = false; + + setPositionInfoWindow(); + createTimerInfoWindows(); + GH.windows().totalRedraw(); +} + +void BattleWindow::showStickyQuickSpellWindow() +{ + Settings showStickyQuickSpellWindow = settings.write["battle"]["enableQuickSpellPanel"]; + showStickyQuickSpellWindow->Bool() = true; + + if(GH.screenDimensions().x >= 1050) + { + quickSpellWindow->enable(); + quickSpellWindow->isEnabled = true; + } + else + { + quickSpellWindow->disable(); + quickSpellWindow->isEnabled = false; + } + + setPositionInfoWindow(); + createTimerInfoWindows(); + GH.windows().totalRedraw(); +} + void BattleWindow::createTimerInfoWindows() { OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; + int xOffsetAttacker = quickSpellWindow->isEnabled ? -53 : 0; + if(LOCPLINT->cb->getStartInfo()->turnTimerInfo.battleTimer != 0 || LOCPLINT->cb->getStartInfo()->turnTimerInfo.unitTimer != 0) { PlayerColor attacker = owner.getBattle()->sideToPlayer(BattleSide::ATTACKER); @@ -176,7 +248,7 @@ void BattleWindow::createTimerInfoWindows() if (attacker.isValidPlayer()) { if (GH.screenDimensions().x >= 1000) - attackerTimerWidget = std::make_shared(Point(-92, 1), attacker); + attackerTimerWidget = std::make_shared(Point(-92 + xOffsetAttacker, 1), attacker); else attackerTimerWidget = std::make_shared(Point(1, 135), attacker); } @@ -199,6 +271,24 @@ std::shared_ptr BattleWindow::buildBattleConsole(const JsonNode & return std::make_shared(owner, background, rect.topLeft(), offset, rect.dimensions() ); } +void BattleWindow::useSpellIfPossible(int slot) +{ + std::string spellIdentifier = persistentStorage["quickSpell"][std::to_string(slot)].String(); + SpellID id; + try + { + id = SpellID::decode(spellIdentifier); + } + catch(const IdentifierResolutionException& e) + { + return; + } + if(id.hasValue() && owner.getBattle()->battleGetMyHero() && id.toSpell()->canBeCast(owner.getBattle().get(), spells::Mode::HERO, owner.getBattle()->battleGetMyHero())) + { + owner.castThisSpell(id); + } +}; + void BattleWindow::toggleQueueVisibility() { if(settings["battle"]["showQueue"].Bool()) @@ -283,10 +373,12 @@ void BattleWindow::showStickyHeroWindows() void BattleWindow::updateQueue() { queue->update(); + createQuickSpellWindow(); } void BattleWindow::setPositionInfoWindow() { + int xOffsetAttacker = quickSpellWindow->isEnabled ? -53 : 0; if(defenderHeroWindow) { Point position = (GH.screenDimensions().x >= 1000) @@ -297,7 +389,7 @@ void BattleWindow::setPositionInfoWindow() if(attackerHeroWindow) { Point position = (GH.screenDimensions().x >= 1000) - ? Point(pos.x - 93, pos.y + 60) + ? Point(pos.x - 93 + xOffsetAttacker, pos.y + 60) : Point(pos.x + 1, pos.y + 195); attackerHeroWindow->moveTo(position); } @@ -311,7 +403,7 @@ void BattleWindow::setPositionInfoWindow() if(attackerStackWindow) { Point position = (GH.screenDimensions().x >= 1000) - ? Point(pos.x - 93, attackerHeroWindow ? attackerHeroWindow->pos.y + 210 : pos.y + 60) + ? Point(pos.x - 93 + xOffsetAttacker, attackerHeroWindow ? attackerHeroWindow->pos.y + 210 : pos.y + 60) : Point(pos.x + 1, attackerHeroWindow ? attackerHeroWindow->pos.y : pos.y + 195); attackerStackWindow->moveTo(position); } @@ -346,6 +438,7 @@ void BattleWindow::updateStackInfoWindow(const CStack * stack) attackerStackWindow = nullptr; setPositionInfoWindow(); + createTimerInfoWindows(); } void BattleWindow::heroManaPointsChanged(const CGHeroInstance * hero) @@ -765,6 +858,8 @@ void BattleWindow::blockUI(bool on) setShortcutBlocked(EShortcut::BATTLE_TACTICS_NEXT, on || !owner.tacticsMode); setShortcutBlocked(EShortcut::BATTLE_CONSOLE_DOWN, on && !owner.tacticsMode); setShortcutBlocked(EShortcut::BATTLE_CONSOLE_UP, on && !owner.tacticsMode); + + quickSpellWindow->setInputEnabled(!on); } void BattleWindow::bOpenActiveUnit() diff --git a/client/battle/BattleWindow.h b/client/battle/BattleWindow.h index 8b6b4f30d..e9246179b 100644 --- a/client/battle/BattleWindow.h +++ b/client/battle/BattleWindow.h @@ -27,6 +27,7 @@ class StackQueue; class TurnTimerWidget; class HeroInfoBasicPanel; class StackInfoBasicPanel; +class QuickSpellPanel; /// GUI object that handles functionality of panel at the bottom of combat screen class BattleWindow : public InterfaceObjectConfigurable @@ -40,6 +41,8 @@ class BattleWindow : public InterfaceObjectConfigurable std::shared_ptr attackerStackWindow; std::shared_ptr defenderStackWindow; + std::shared_ptr quickSpellWindow; + std::shared_ptr attackerTimerWidget; std::shared_ptr defenderTimerWidget; @@ -68,12 +71,16 @@ class BattleWindow : public InterfaceObjectConfigurable PossiblePlayerBattleAction lastAlternativeAction; void showAlternativeActionIcon(PossiblePlayerBattleAction); + void useSpellIfPossible(int slot); + /// flip battle queue visibility to opposite void toggleQueueVisibility(); void createQueue(); void toggleStickyHeroWindowsVisibility(); + void toggleStickyQuickSpellVisibility(); void createStickyHeroInfoWindows(); + void createQuickSpellWindow(); void createTimerInfoWindows(); std::shared_ptr buildBattleConsole(const JsonNode &) const; @@ -94,6 +101,10 @@ public: void hideStickyHeroWindows(); void showStickyHeroWindows(); + /// Toggle permanent quickspell windows visibility + void hideStickyQuickSpellWindow(); + void showStickyQuickSpellWindow(); + /// Event handler for netpack changing hero mana points void heroManaPointsChanged(const CGHeroInstance * hero); diff --git a/client/gui/Shortcut.h b/client/gui/Shortcut.h index ebe89e4e2..aedf695d9 100644 --- a/client/gui/Shortcut.h +++ b/client/gui/Shortcut.h @@ -186,6 +186,19 @@ enum class EShortcut BATTLE_TOGGLE_HEROES_STATS, BATTLE_OPEN_ACTIVE_UNIT, BATTLE_OPEN_HOVERED_UNIT, + BATTLE_TOGGLE_QUICKSPELL, + BATTLE_SPELL_SHORTCUT_0, + BATTLE_SPELL_SHORTCUT_1, + BATTLE_SPELL_SHORTCUT_2, + BATTLE_SPELL_SHORTCUT_3, + BATTLE_SPELL_SHORTCUT_4, + BATTLE_SPELL_SHORTCUT_5, + BATTLE_SPELL_SHORTCUT_6, + BATTLE_SPELL_SHORTCUT_7, + BATTLE_SPELL_SHORTCUT_8, + BATTLE_SPELL_SHORTCUT_9, + BATTLE_SPELL_SHORTCUT_10, + BATTLE_SPELL_SHORTCUT_11, MARKET_DEAL, MARKET_MAX_AMOUNT, diff --git a/client/gui/ShortcutHandler.cpp b/client/gui/ShortcutHandler.cpp index 3a5033882..259a1c6cb 100644 --- a/client/gui/ShortcutHandler.cpp +++ b/client/gui/ShortcutHandler.cpp @@ -222,6 +222,19 @@ EShortcut ShortcutHandler::findShortcut(const std::string & identifier ) const {"battleTacticsNext", EShortcut::BATTLE_TACTICS_NEXT }, {"battleTacticsEnd", EShortcut::BATTLE_TACTICS_END }, {"battleSelectAction", EShortcut::BATTLE_SELECT_ACTION }, + {"battleToggleQuickSpell", EShortcut::BATTLE_TOGGLE_QUICKSPELL }, + {"battleSpellShortcut0", EShortcut::BATTLE_SPELL_SHORTCUT_0 }, + {"battleSpellShortcut1", EShortcut::BATTLE_SPELL_SHORTCUT_1 }, + {"battleSpellShortcut2", EShortcut::BATTLE_SPELL_SHORTCUT_2 }, + {"battleSpellShortcut3", EShortcut::BATTLE_SPELL_SHORTCUT_3 }, + {"battleSpellShortcut4", EShortcut::BATTLE_SPELL_SHORTCUT_4 }, + {"battleSpellShortcut5", EShortcut::BATTLE_SPELL_SHORTCUT_5 }, + {"battleSpellShortcut6", EShortcut::BATTLE_SPELL_SHORTCUT_6 }, + {"battleSpellShortcut7", EShortcut::BATTLE_SPELL_SHORTCUT_7 }, + {"battleSpellShortcut8", EShortcut::BATTLE_SPELL_SHORTCUT_8 }, + {"battleSpellShortcut9", EShortcut::BATTLE_SPELL_SHORTCUT_9 }, + {"battleSpellShortcut10", EShortcut::BATTLE_SPELL_SHORTCUT_10 }, + {"battleSpellShortcut11", EShortcut::BATTLE_SPELL_SHORTCUT_11 }, {"spectateTrackHero", EShortcut::SPECTATE_TRACK_HERO }, {"spectateSkipBattle", EShortcut::SPECTATE_SKIP_BATTLE }, {"spectateSkipBattleResult", EShortcut::SPECTATE_SKIP_BATTLE_RESULT }, diff --git a/client/widgets/Buttons.cpp b/client/widgets/Buttons.cpp index 620c08587..4ab499cd7 100644 --- a/client/widgets/Buttons.cpp +++ b/client/widgets/Buttons.cpp @@ -67,6 +67,11 @@ void CButton::addCallback(const std::function & callback) this->callback += callback; } +void CButton::addPopupCallback(const std::function & callback) +{ + this->callbackPopup += callback; +} + void ButtonBase::setTextOverlay(const std::string & Text, EFonts font, ColorRGBA color) { OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); @@ -289,6 +294,8 @@ void CButton::clickCancel(const Point & cursorPosition) void CButton::showPopupWindow(const Point & cursorPosition) { + callbackPopup(); + if(!helpBox.empty()) //there is no point to show window with nothing inside... CRClickPopup::createAndPush(helpBox); } diff --git a/client/widgets/Buttons.h b/client/widgets/Buttons.h index e5bad6aab..34d97ec83 100644 --- a/client/widgets/Buttons.h +++ b/client/widgets/Buttons.h @@ -69,6 +69,7 @@ public: class CButton : public ButtonBase { CFunctionList callback; + CFunctionList callbackPopup; std::array hoverTexts; //texts for statusbar, if empty - first entry will be used std::optional borderColor; // mapping of button state to border color @@ -90,6 +91,7 @@ public: /// adds one more callback to on-click actions void addCallback(const std::function & callback); + void addPopupCallback(const std::function & callback); void addHoverText(EButtonState state, const std::string & text); diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index 5c89602c3..f20c0e306 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -98,13 +98,15 @@ public: } }; -CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _myInt, bool openOnBattleSpells): +CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _myInt, bool openOnBattleSpells, std::function onSpellSelect): CWindowObject(PLAYER_COLORED | (settings["gameTweaks"]["enableLargeSpellbook"].Bool() ? BORDERED : 0)), battleSpellsOnly(openOnBattleSpells), selectedTab(4), currentPage(0), myHero(_myHero), myInt(_myInt), + openOnBattleSpells(openOnBattleSpells), + onSpellSelect(onSpellSelect), isBigSpellbook(settings["gameTweaks"]["enableLargeSpellbook"].Bool()), spellsPerPage(24), offL(-11), @@ -293,6 +295,14 @@ void CSpellWindow::processSpells() for(auto const & spell : CGI->spellh->objects) { bool searchTextFound = !searchBox || boost::algorithm::contains(boost::algorithm::to_lower_copy(spell->getNameTranslated()), boost::algorithm::to_lower_copy(searchBox->getText())); + + if(onSpellSelect) + { + if(spell->isCombat() == openOnBattleSpells && !spell->isSpecial() && !spell->isCreatureAbility()) + mySpells.push_back(spell.get()); + continue; + } + if(!spell->isCreatureAbility() && myHero->canCastThisSpell(spell.get()) && searchTextFound) mySpells.push_back(spell.get()); } @@ -602,6 +612,13 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition) { if(mySpell) { + if(owner->onSpellSelect) + { + owner->onSpellSelect(mySpell->id); + owner->fexitb(); + return; + } + auto spellCost = owner->myInt->cb->getSpellCost(mySpell, owner->myHero); if(spellCost > owner->myHero->mana) //insufficient mana { @@ -738,7 +755,7 @@ void CSpellWindow::SpellArea::setSpell(const CSpell * spell) } ColorRGBA firstLineColor, secondLineColor; - if(spellCost > owner->myHero->mana) //hero cannot cast this spell + if(spellCost > owner->myHero->mana && !owner->onSpellSelect) //hero cannot cast this spell { firstLineColor = Colors::WHITE; secondLineColor = Colors::ORANGE; diff --git a/client/windows/CSpellWindow.h b/client/windows/CSpellWindow.h index 16401a752..f9a761547 100644 --- a/client/windows/CSpellWindow.h +++ b/client/windows/CSpellWindow.h @@ -115,8 +115,11 @@ class CSpellWindow : public CWindowObject std::shared_ptr createBigSpellBook(); + bool openOnBattleSpells; + std::function onSpellSelect; //external processing of selected spell + public: - CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _myInt, bool openOnBattleSpells = true); + CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _myInt, bool openOnBattleSpells = true, std::function onSpellSelect = nullptr); ~CSpellWindow(); void fexitb(); diff --git a/config/schemas/settings.json b/config/schemas/settings.json index 002500054..56c97240b 100644 --- a/config/schemas/settings.json +++ b/config/schemas/settings.json @@ -372,7 +372,7 @@ "type" : "object", "additionalProperties" : false, "default" : {}, - "required" : [ "speedFactor", "mouseShadow", "cellBorders", "stackRange", "movementHighlightOnHover", "rangeLimitHighlightOnHover", "showQueue", "swipeAttackDistance", "queueSize", "stickyHeroInfoWindows", "enableAutocombatSpells", "endWithAutocombat", "queueSmallSlots", "queueSmallOutside" ], + "required" : [ "speedFactor", "mouseShadow", "cellBorders", "stackRange", "movementHighlightOnHover", "rangeLimitHighlightOnHover", "showQueue", "swipeAttackDistance", "queueSize", "stickyHeroInfoWindows", "enableAutocombatSpells", "endWithAutocombat", "queueSmallSlots", "queueSmallOutside", "enableQuickSpellPanel" ], "properties" : { "speedFactor" : { "type" : "number", @@ -430,6 +430,10 @@ "queueSmallOutside" : { "type": "boolean", "default": false + }, + "enableQuickSpellPanel" : { + "type": "boolean", + "default": true } } }, diff --git a/config/shortcutsConfig.json b/config/shortcutsConfig.json index ebf1463fb..817d89b96 100644 --- a/config/shortcutsConfig.json +++ b/config/shortcutsConfig.json @@ -64,6 +64,19 @@ "battleOpenHoveredUnit": "V", "battleRetreat": "R", "battleSelectAction": "S", + "battleToggleQuickSpell": "T", + "battleSpellShortcut0": "1", + "battleSpellShortcut1": "2", + "battleSpellShortcut2": "3", + "battleSpellShortcut3": "4", + "battleSpellShortcut4": "5", + "battleSpellShortcut5": "6", + "battleSpellShortcut6": "7", + "battleSpellShortcut7": "8", + "battleSpellShortcut8": "9", + "battleSpellShortcut9": "0", + "battleSpellShortcut10": "N", + "battleSpellShortcut11": "M", "battleSurrender": "S", "battleTacticsEnd": [ "Return", "Keypad Enter"], "battleTacticsNext": "Space",