diff --git a/client/battle/BattleActionsController.cpp b/client/battle/BattleActionsController.cpp index 638efbf14..68a4a0aef 100644 --- a/client/battle/BattleActionsController.cpp +++ b/client/battle/BattleActionsController.cpp @@ -759,7 +759,30 @@ void BattleActionsController::activateStack() { const CStack * s = owner.stacksController->getActiveStack(); if(s) + { possibleActions = getPossibleActionsForStack(s); + std::list actionsToSelect; + if(!possibleActions.empty()) + { + switch(possibleActions.front()) + { + case PossiblePlayerBattleAction::SHOOT: + actionsToSelect.push_back(possibleActions.front()); + actionsToSelect.push_back(PossiblePlayerBattleAction::ATTACK); + break; + + case PossiblePlayerBattleAction::ATTACK_AND_RETURN: + actionsToSelect.push_back(possibleActions.front()); + actionsToSelect.push_back(PossiblePlayerBattleAction::WALK_AND_ATTACK); + break; + + case PossiblePlayerBattleAction::AIMED_SPELL_CREATURE: + actionsToSelect.push_back(possibleActions.front()); + break; + } + } + owner.controlPanel->setAlternativeActions(actionsToSelect); + } } bool BattleActionsController::spellcastingModeActive() const @@ -773,3 +796,18 @@ SpellID BattleActionsController::selectedSpell() const return SpellID::NONE; return SpellID(spellToCast->actionSubtype); } + +const std::vector & BattleActionsController::getPossibleActions() const +{ + return possibleActions; +} + +void BattleActionsController::removePossibleAction(PossiblePlayerBattleAction action) +{ + vstd::erase(possibleActions, action); +} + +void BattleActionsController::pushFrontPossibleAction(PossiblePlayerBattleAction action) +{ + possibleActions.insert(possibleActions.begin(), action); +} diff --git a/client/battle/BattleActionsController.h b/client/battle/BattleActionsController.h index 74b55b983..7b17c2faa 100644 --- a/client/battle/BattleActionsController.h +++ b/client/battle/BattleActionsController.h @@ -92,5 +92,12 @@ public: /// returns true if UI is currently in target selection mode bool spellcastingModeActive() const; + + /// methods to work with array of possible actions, needed to control special creatures abilities + const std::vector & getPossibleActions() const; + void removePossibleAction(PossiblePlayerBattleAction); + + /// inserts possible action in the beggining in order to prioritize it + void pushFrontPossibleAction(PossiblePlayerBattleAction); }; diff --git a/client/battle/BattleControlPanel.cpp b/client/battle/BattleControlPanel.cpp index e2d295c20..67808f6f2 100644 --- a/client/battle/BattleControlPanel.cpp +++ b/client/battle/BattleControlPanel.cpp @@ -19,6 +19,7 @@ #include "../CPlayerInterface.h" #include "../gui/CCursorHandler.h" #include "../gui/CGuiHandler.h" +#include "../gui/CAnimation.h" #include "../windows/CSpellWindow.h" #include "../widgets/Buttons.h" #include "../widgets/Images.h" @@ -43,14 +44,15 @@ BattleControlPanel::BattleControlPanel(BattleInterface & owner, const Point & po bSpell = std::make_shared (Point(645, 5), "icm005.def", CGI->generaltexth->zelp[385], std::bind(&BattleControlPanel::bSpellf,this), SDLK_c); bWait = std::make_shared (Point(696, 5), "icm006.def", CGI->generaltexth->zelp[386], std::bind(&BattleControlPanel::bWaitf,this), SDLK_w); bDefence = std::make_shared (Point(747, 5), "icm007.def", CGI->generaltexth->zelp[387], std::bind(&BattleControlPanel::bDefencef,this), SDLK_d); - bConsoleUp = std::make_shared (Point(624, 5), "ComSlide.def", std::make_pair("", ""), std::bind(&BattleControlPanel::bConsoleUpf,this), SDLK_UP); - bConsoleDown = std::make_shared(Point(624, 24), "ComSlide.def", std::make_pair("", ""), std::bind(&BattleControlPanel::bConsoleDownf,this), SDLK_DOWN); + bSwitchAction = std::make_shared(Point(589, 5), "icmalt00", CGI->generaltexth->zelp[387], std::bind(&BattleControlPanel::bSwitchActionf,this), SDLK_r); + bConsoleUp = std::make_shared (Point(578, 5), "ComSlide.def", std::make_pair("", ""), std::bind(&BattleControlPanel::bConsoleUpf,this), SDLK_UP); + bConsoleDown = std::make_shared(Point(578, 24), "ComSlide.def", std::make_pair("", ""), std::bind(&BattleControlPanel::bConsoleDownf,this), SDLK_DOWN); bDefence->assignedKeys.insert(SDLK_SPACE); bConsoleUp->setImageOrder(0, 1, 0, 0); bConsoleDown->setImageOrder(2, 3, 2, 2); - console = std::make_shared(Rect(211, 4, 406,38)); + console = std::make_shared(Rect(211, 4, 350 ,38)); GH.statusbar = console; if ( owner.tacticsMode ) @@ -174,6 +176,52 @@ void BattleControlPanel::reallySurrender() } } +void BattleControlPanel::showAlternativeActionIcon(PossiblePlayerBattleAction action) +{ + std::string iconName = "icmalt00"; + switch(action) + { + case PossiblePlayerBattleAction::ATTACK: + iconName = "icmalt01"; + break; + + case PossiblePlayerBattleAction::SHOOT: + iconName = "icmalt02"; + break; + + case PossiblePlayerBattleAction::AIMED_SPELL_CREATURE: + iconName = "icmalt03"; + break; + + //case PossiblePlayerBattleAction::ATTACK_AND_RETURN: + //iconName = "icmalt04"; + //break; + + case PossiblePlayerBattleAction::ATTACK_AND_RETURN: + iconName = "icmalt05"; + break; + + case PossiblePlayerBattleAction::WALK_AND_ATTACK: + iconName = "icmalt06"; + break; + } + + auto anim = std::make_shared(iconName); + bSwitchAction->setImage(anim, false); +} + +void BattleControlPanel::setAlternativeActions(const std::list & actions) +{ + alternativeActions = actions; + defaultAction = PossiblePlayerBattleAction::INVALID; + if(alternativeActions.size() > 1) + defaultAction = alternativeActions.back(); + if(!alternativeActions.empty()) + showAlternativeActionIcon(alternativeActions.front()); + else + showAlternativeActionIcon(defaultAction); +} + void BattleControlPanel::bAutofightf() { if (owner.actionsController->spellcastingModeActive()) @@ -243,6 +291,33 @@ void BattleControlPanel::bSpellf() } } +void BattleControlPanel::bSwitchActionf() +{ + if(alternativeActions.empty()) + return; + + if(alternativeActions.front() == defaultAction) + { + alternativeActions.push_back(alternativeActions.front()); + alternativeActions.pop_front(); + } + + auto actions = owner.actionsController->getPossibleActions(); + if(!actions.empty() && actions.front() == alternativeActions.front()) + { + owner.actionsController->removePossibleAction(alternativeActions.front()); + showAlternativeActionIcon(defaultAction); + } + else + { + owner.actionsController->pushFrontPossibleAction(alternativeActions.front()); + showAlternativeActionIcon(alternativeActions.front()); + } + + alternativeActions.push_back(alternativeActions.front()); + alternativeActions.pop_front(); +} + void BattleControlPanel::bWaitf() { if (owner.actionsController->spellcastingModeActive()) diff --git a/client/battle/BattleControlPanel.h b/client/battle/BattleControlPanel.h index 433a2717f..f8805a59b 100644 --- a/client/battle/BattleControlPanel.h +++ b/client/battle/BattleControlPanel.h @@ -10,6 +10,7 @@ #pragma once #include "../gui/CIntObject.h" +#include "../../lib/battle/CBattleInfoCallback.h" VCMI_LIB_NAMESPACE_BEGIN class CStack; @@ -31,6 +32,7 @@ class BattleControlPanel : public CIntObject std::shared_ptr bSurrender; std::shared_ptr bFlee; std::shared_ptr bAutofight; + std::shared_ptr bSwitchAction; std::shared_ptr bSpell; std::shared_ptr bWait; std::shared_ptr bDefence; @@ -46,6 +48,7 @@ class BattleControlPanel : public CIntObject void bAutofightf(); void bSpellf(); void bWaitf(); + void bSwitchActionf(); void bDefencef(); void bConsoleUpf(); void bConsoleDownf(); @@ -55,6 +58,11 @@ class BattleControlPanel : public CIntObject /// functions for handling actions after they were confirmed by popup window void reallyFlee(); void reallySurrender(); + + /// management of alternative actions + std::list alternativeActions; + PossiblePlayerBattleAction defaultAction; + void showAlternativeActionIcon(PossiblePlayerBattleAction); public: std::shared_ptr console; @@ -70,6 +78,9 @@ public: /// Toggle UI to displaying battle log in place of tactics UI void tacticPhaseEnded(); + + /// Set possible alternative options. If more than 1 - the last will be considered as default option + void setAlternativeActions(const std::list &); BattleControlPanel(BattleInterface & owner, const Point & position); };