1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Separated battle control panel into new class, refactoring of

CGStatusBar to allow shared API with battle console
This commit is contained in:
Ivan Savenko 2022-11-18 17:54:10 +02:00
parent 3c5858f01e
commit 7a6ad671ab
20 changed files with 522 additions and 503 deletions

View File

@ -3,6 +3,7 @@ set(client_SRCS
../CCallback.cpp
battle/CBattleAnimations.cpp
battle/CBattleControlPanel.cpp
battle/CBattleInterfaceClasses.cpp
battle/CBattleInterface.cpp
battle/CBattleFieldController.cpp
@ -80,6 +81,7 @@ set(client_HEADERS
StdInc.h
battle/CBattleAnimations.h
battle/CBattleControlPanel.h
battle/CBattleInterfaceClasses.h
battle/CBattleInterface.h
battle/CBattleFieldController.h

View File

@ -15,6 +15,7 @@
#include "battle/CBattleInterface.h"
#include "battle/CBattleFieldController.h"
#include "battle/CBattleInterfaceClasses.h"
#include "battle/CBattleControlPanel.h"
#include "../CCallback.h"
#include "windows/CCastleInterface.h"
#include "gui/CCursorHandler.h"
@ -1028,19 +1029,19 @@ void CPlayerInterface::battleAttack(const BattleAttack * ba)
if(ba->lucky()) //lucky hit
{
battleInt->console->addText(attacker->formatGeneralMessage(-45));
battleInt->controlPanel->console->addText(attacker->formatGeneralMessage(-45));
battleInt->displayEffect(18, attacker->getPosition());
CCS->soundh->playSound(soundBase::GOODLUCK);
}
if(ba->unlucky()) //unlucky hit
{
battleInt->console->addText(attacker->formatGeneralMessage(-44));
battleInt->controlPanel->console->addText(attacker->formatGeneralMessage(-44));
battleInt->displayEffect(48, attacker->getPosition());
CCS->soundh->playSound(soundBase::BADLUCK);
}
if(ba->deathBlow())
{
battleInt->console->addText(attacker->formatGeneralMessage(365));
battleInt->controlPanel->console->addText(attacker->formatGeneralMessage(365));
for(auto & elem : ba->bsa)
{
const CStack * attacked = cb->battleGetStackByID(elem.stackAttacked);

View File

@ -0,0 +1,304 @@
/*
* CBattleControlPanel.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "CBattleControlPanel.h"
#include "CBattleInterface.h"
#include "CBattleInterfaceClasses.h"
#include "../widgets/Buttons.h"
#include "../CGameInfo.h"
#include "../CBitmapHandler.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../CPlayerInterface.h"
#include "../../CCallback.h"
#include "../gui/CCursorHandler.h"
#include "../gui/CGuiHandler.h"
#include "../windows/CSpellWindow.h"
#include "../../lib/CStack.h"
#include "../../lib/CConfigHandler.h"
CBattleControlPanel::CBattleControlPanel(CBattleInterface * owner):
owner(owner)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
//preparing buttons and console
bOptions = std::make_shared<CButton> (Point( 3, 5), "icm003.def", CGI->generaltexth->zelp[381], std::bind(&CBattleControlPanel::bOptionsf,this), SDLK_o);
bSurrender = std::make_shared<CButton> (Point( 54, 5), "icm001.def", CGI->generaltexth->zelp[379], std::bind(&CBattleControlPanel::bSurrenderf,this), SDLK_s);
bFlee = std::make_shared<CButton> (Point(105, 5), "icm002.def", CGI->generaltexth->zelp[380], std::bind(&CBattleControlPanel::bFleef,this), SDLK_r);
bAutofight = std::make_shared<CButton> (Point(157, 5), "icm004.def", CGI->generaltexth->zelp[382], std::bind(&CBattleControlPanel::bAutofightf,this), SDLK_a);
bSpell = std::make_shared<CButton> (Point(645, 5), "icm005.def", CGI->generaltexth->zelp[385], std::bind(&CBattleControlPanel::bSpellf,this), SDLK_c);
bWait = std::make_shared<CButton> (Point(696, 5), "icm006.def", CGI->generaltexth->zelp[386], std::bind(&CBattleControlPanel::bWaitf,this), SDLK_w);
bDefence = std::make_shared<CButton> (Point(747, 5), "icm007.def", CGI->generaltexth->zelp[387], std::bind(&CBattleControlPanel::bDefencef,this), SDLK_d);
bConsoleUp = std::make_shared<CButton> (Point(624, 5), "ComSlide.def", std::make_pair("", ""), std::bind(&CBattleControlPanel::bConsoleUpf,this), SDLK_UP);
bConsoleDown = std::make_shared<CButton>(Point(624, 24), "ComSlide.def", std::make_pair("", ""), std::bind(&CBattleControlPanel::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<CBattleConsole>(Rect(211, 4, 406,38));
GH.statusbar = console;
if ( owner->tacticsMode )
tacticPhaseStarted();
else
tacticPhaseEnded();
}
void CBattleControlPanel::tacticPhaseStarted()
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
btactNext = std::make_shared<CButton>(Point(213, 4), "icm011.def", std::make_pair("", ""), [&]() { bTacticNextStack();}, SDLK_SPACE);
btactEnd = std::make_shared<CButton>(Point(419, 4), "icm012.def", std::make_pair("", ""), [&](){ bTacticPhaseEnd();}, SDLK_RETURN);
menu = std::make_shared<CPicture>("COPLACBR.BMP", 0, 0);
menu->colorize(owner->curInt->playerID);
}
void CBattleControlPanel::tacticPhaseEnded()
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
menu = std::make_shared<CPicture>("CBAR.BMP", 0, 0);
menu->colorize(owner->curInt->playerID);
}
void CBattleControlPanel::bOptionsf()
{
if (owner->spellDestSelectMode) //we are casting a spell
return;
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
Rect tempRect = genRect(431, 481, 160, 84);
tempRect += pos.topLeft();
GH.pushIntT<CBattleOptionsWindow>(tempRect, owner);
}
void CBattleControlPanel::bSurrenderf()
{
if(owner->spellDestSelectMode) //we are casting a spell
return;
int cost = owner->curInt->cb->battleGetSurrenderCost();
if(cost >= 0)
{
std::string enemyHeroName = owner->curInt->cb->battleGetEnemyHero().name;
if(enemyHeroName.empty())
{
logGlobal->warn("Surrender performed without enemy hero, should not happen!");
enemyHeroName = "#ENEMY#";
}
std::string surrenderMessage = boost::str(boost::format(CGI->generaltexth->allTexts[32]) % enemyHeroName % cost); //%s states: "I will accept your surrender and grant you and your troops safe passage for the price of %d gold."
owner->curInt->showYesNoDialog(surrenderMessage, [this](){ reallySurrender(); }, nullptr);
}
}
void CBattleControlPanel::bFleef()
{
if (owner->spellDestSelectMode) //we are casting a spell
return;
if ( owner->curInt->cb->battleCanFlee() )
{
CFunctionList<void()> ony = std::bind(&CBattleControlPanel::reallyFlee,this);
owner->curInt->showYesNoDialog(CGI->generaltexth->allTexts[28], ony, nullptr); //Are you sure you want to retreat?
}
else
{
std::vector<std::shared_ptr<CComponent>> comps;
std::string heroName;
//calculating fleeing hero's name
if (owner->attackingHeroInstance)
if (owner->attackingHeroInstance->tempOwner == owner->curInt->cb->getMyColor())
heroName = owner->attackingHeroInstance->name;
if (owner->defendingHeroInstance)
if (owner->defendingHeroInstance->tempOwner == owner->curInt->cb->getMyColor())
heroName = owner->defendingHeroInstance->name;
//calculating text
auto txt = boost::format(CGI->generaltexth->allTexts[340]) % heroName; //The Shackles of War are present. %s can not retreat!
//printing message
owner->curInt->showInfoDialog(boost::to_string(txt), comps);
}
}
void CBattleControlPanel::reallyFlee()
{
owner->giveCommand(EActionType::RETREAT);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
void CBattleControlPanel::reallySurrender()
{
if (owner->curInt->cb->getResourceAmount(Res::GOLD) < owner->curInt->cb->battleGetSurrenderCost())
{
owner->curInt->showInfoDialog(CGI->generaltexth->allTexts[29]); //You don't have enough gold!
}
else
{
owner->giveCommand(EActionType::SURRENDER);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
}
void CBattleControlPanel::bAutofightf()
{
if(owner->spellDestSelectMode) //we are casting a spell
return;
//Stop auto-fight mode
if(owner->curInt->isAutoFightOn)
{
assert(owner->curInt->autofightingAI);
owner->curInt->isAutoFightOn = false;
logGlobal->trace("Stopping the autofight...");
}
else if(!owner->curInt->autofightingAI)
{
owner->curInt->isAutoFightOn = true;
blockUI(true);
auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
ai->init(owner->curInt->env, owner->curInt->cb);
ai->battleStart(owner->army1, owner->army2, int3(0,0,0), owner->attackingHeroInstance, owner->defendingHeroInstance, owner->curInt->cb->battleGetMySide());
owner->curInt->autofightingAI = ai;
owner->curInt->cb->registerBattleInterface(ai);
owner->requestAutofightingAIToTakeAction();
}
}
void CBattleControlPanel::bSpellf()
{
if (owner->spellDestSelectMode) //we are casting a spell
return;
if (!owner->myTurn)
return;
auto myHero = owner->currentHero();
if(!myHero)
return;
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
ESpellCastProblem::ESpellCastProblem spellCastProblem = owner->curInt->cb->battleCanCastSpell(myHero, spells::Mode::HERO);
if(spellCastProblem == ESpellCastProblem::OK)
{
GH.pushIntT<CSpellWindow>(myHero, owner->curInt.get());
}
else if (spellCastProblem == ESpellCastProblem::MAGIC_IS_BLOCKED)
{
//TODO: move to spell mechanics, add more information to spell cast problem
//Handle Orb of Inhibition-like effects -> we want to display dialog with info, why casting is impossible
auto blockingBonus = owner->currentHero()->getBonusLocalFirst(Selector::type()(Bonus::BLOCK_ALL_MAGIC));
if (!blockingBonus)
return;
if (blockingBonus->source == Bonus::ARTIFACT)
{
const int32_t artID = blockingBonus->sid;
//If we have artifact, put name of our hero. Otherwise assume it's the enemy.
//TODO check who *really* is source of bonus
std::string heroName = myHero->hasArt(artID) ? myHero->name : owner->enemyHero().name;
//%s wields the %s, an ancient artifact which creates a p dead to all magic.
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[683])
% heroName % CGI->artifacts()->getByIndex(artID)->getName()));
}
}
}
void CBattleControlPanel::bWaitf()
{
if (owner->spellDestSelectMode) //we are casting a spell
return;
if (owner->activeStack != nullptr)
owner->giveCommand(EActionType::WAIT);
}
void CBattleControlPanel::bDefencef()
{
if (owner->spellDestSelectMode) //we are casting a spell
return;
if (owner->activeStack != nullptr)
owner->giveCommand(EActionType::DEFEND);
}
void CBattleControlPanel::bConsoleUpf()
{
if (owner->spellDestSelectMode) //we are casting a spell
return;
console->scrollUp();
}
void CBattleControlPanel::bConsoleDownf()
{
if (owner->spellDestSelectMode) //we are casting a spell
return;
console->scrollDown();
}
void CBattleControlPanel::bTacticNextStack()
{
owner->tacticNextStack(nullptr);
}
void CBattleControlPanel::bTacticPhaseEnd()
{
owner->tacticPhaseEnd();
}
void CBattleControlPanel::blockUI(bool on)
{
bool canCastSpells = false;
auto hero = owner->curInt->cb->battleGetMyHero();
if(hero)
{
ESpellCastProblem::ESpellCastProblem spellcastingProblem = owner->curInt->cb->battleCanCastSpell(hero, spells::Mode::HERO);
//if magic is blocked, we leave button active, so the message can be displayed after button click
canCastSpells = spellcastingProblem == ESpellCastProblem::OK || spellcastingProblem == ESpellCastProblem::MAGIC_IS_BLOCKED;
}
bool canWait = owner->activeStack ? !owner->activeStack->waitedThisTurn : false;
bOptions->block(on);
bFlee->block(on || !owner->curInt->cb->battleCanFlee());
bSurrender->block(on || owner->curInt->cb->battleGetSurrenderCost() < 0);
// block only if during enemy turn and auto-fight is off
// otherwise - crash on accessing non-exisiting active stack
bAutofight->block(!owner->curInt->isAutoFightOn && !owner->activeStack);
if (owner->tacticsMode && btactEnd && btactNext)
{
btactNext->block(on);
btactEnd->block(on);
}
else
{
bConsoleUp->block(on);
bConsoleDown->block(on);
}
bSpell->block(on || owner->tacticsMode || !canCastSpells);
bWait->block(on || owner->tacticsMode || !canWait);
bDefence->block(on || owner->tacticsMode);
}

View File

@ -0,0 +1,64 @@
/*
* CBattleControlPanel.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../gui/CIntObject.h"
class CStack;
class CButton;
class CBattleInterface;
class CBattleConsole;
class CBattleControlPanel : public CIntObject
{
CBattleInterface * owner;
std::shared_ptr<CPicture> menu;
std::shared_ptr<CButton> bOptions;
std::shared_ptr<CButton> bSurrender;
std::shared_ptr<CButton> bFlee;
std::shared_ptr<CButton> bAutofight;
std::shared_ptr<CButton> bSpell;
std::shared_ptr<CButton> bWait;
std::shared_ptr<CButton> bDefence;
std::shared_ptr<CButton> bConsoleUp;
std::shared_ptr<CButton> bConsoleDown;
std::shared_ptr<CButton> btactNext;
std::shared_ptr<CButton> btactEnd;
//button handle funcs:
void bOptionsf();
void bSurrenderf();
void bFleef();
void reallyFlee(); //performs fleeing without asking player
void reallySurrender(); //performs surrendering without asking player
void bAutofightf();
void bSpellf();
void bWaitf();
void bDefencef();
void bConsoleUpf();
void bConsoleDownf();
void bTacticNextStack();
void bTacticPhaseEnd();
public:
std::shared_ptr<CBattleConsole> console;
// block all UI elements, e.g. during enemy turn
// unlike activate/deactivate this method will correctly grey-out all elements
void blockUI(bool on);
void tacticPhaseStarted();
void tacticPhaseEnded();
CBattleControlPanel(CBattleInterface * owner);
};

View File

@ -17,6 +17,7 @@
#include "CBattleObstacleController.h"
#include "CBattleSiegeController.h"
#include "CBattleFieldController.h"
#include "CBattleControlPanel.h"
#include "../CBitmapHandler.h"
#include "../CGameInfo.h"
@ -200,37 +201,6 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
CSDL_Ext::alphaTransform(amountEffNeutral);
transformPalette(amountEffNeutral, 1.00, 1.00, 0.18);
//preparing buttons and console
bOptions = std::make_shared<CButton>(Point( 3, 561), "icm003.def", CGI->generaltexth->zelp[381], std::bind(&CBattleInterface::bOptionsf,this), SDLK_o);
bSurrender = std::make_shared<CButton>(Point( 54, 561), "icm001.def", CGI->generaltexth->zelp[379], std::bind(&CBattleInterface::bSurrenderf,this), SDLK_s);
bFlee = std::make_shared<CButton>(Point(105, 561), "icm002.def", CGI->generaltexth->zelp[380], std::bind(&CBattleInterface::bFleef,this), SDLK_r);
bAutofight = std::make_shared<CButton>(Point(157, 561), "icm004.def", CGI->generaltexth->zelp[382], std::bind(&CBattleInterface::bAutofightf,this), SDLK_a);
bSpell = std::make_shared<CButton>(Point(645, 561), "icm005.def", CGI->generaltexth->zelp[385], std::bind(&CBattleInterface::bSpellf,this), SDLK_c);
bWait = std::make_shared<CButton>(Point(696, 561), "icm006.def", CGI->generaltexth->zelp[386], std::bind(&CBattleInterface::bWaitf,this), SDLK_w);
bDefence = std::make_shared<CButton>(Point(747, 561), "icm007.def", CGI->generaltexth->zelp[387], std::bind(&CBattleInterface::bDefencef,this), SDLK_d);
bDefence->assignedKeys.insert(SDLK_SPACE);
bConsoleUp = std::make_shared<CButton>(Point(624, 561), "ComSlide.def", std::make_pair("", ""), std::bind(&CBattleInterface::bConsoleUpf,this), SDLK_UP);
bConsoleDown = std::make_shared<CButton>(Point(624, 580), "ComSlide.def", std::make_pair("", ""), std::bind(&CBattleInterface::bConsoleDownf,this), SDLK_DOWN);
bConsoleUp->setImageOrder(0, 1, 0, 0);
bConsoleDown->setImageOrder(2, 3, 2, 2);
console = std::make_shared<CBattleConsole>();
console->pos.x += 211;
console->pos.y += 560;
console->pos.w = 406;
console->pos.h = 38;
if(tacticsMode)
{
btactNext = std::make_shared<CButton>(Point(213, 560), "icm011.def", std::make_pair("", ""), [&](){ bTacticNextStack(nullptr);}, SDLK_SPACE);
btactEnd = std::make_shared<CButton>(Point(419, 560), "icm012.def", std::make_pair("", ""), [&](){ bEndTacticPhase();}, SDLK_RETURN);
menu = BitmapHandler::loadBitmap("COPLACBR.BMP");
}
else
{
menu = BitmapHandler::loadBitmap("CBAR.BMP");
}
graphics->blueToPlayersAdv(menu, curInt->playerID);
//loading hero animations
if(hero1) // attacking hero
{
@ -281,7 +251,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
obstacleController.reset(new CBattleObstacleController(this));
if(tacticsMode)
bTacticNextStack();
tacticNextStack(nullptr);
CCS->musich->stopMusic();
battleIntroSoundChannel = CCS->soundh->playSoundFromSet(CCS->soundh->battleIntroSounds);
@ -291,7 +261,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
{
CCS->musich->playMusicFromSet("battle", true, true);
battleActionsStarted = true;
blockUI(settings["session"]["spectate"].Bool());
controlPanel->blockUI(settings["session"]["spectate"].Bool());
battleIntroSoundChannel = -1;
}
};
@ -301,7 +271,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
currentAction = PossiblePlayerBattleAction::INVALID;
selectedAction = PossiblePlayerBattleAction::INVALID;
addUsedEvents(RCLICK | MOVE | KEYBOARD);
blockUI(true);
controlPanel->blockUI(true);
}
CBattleInterface::~CBattleInterface()
@ -313,7 +283,6 @@ CBattleInterface::~CBattleInterface()
{
deactivate();
}
SDL_FreeSurface(menu);
SDL_FreeSurface(amountNormal);
SDL_FreeSurface(amountNegative);
SDL_FreeSurface(amountPositive);
@ -357,20 +326,12 @@ void CBattleInterface::setPrintMouseShadow(bool set)
void CBattleInterface::activate()
{
controlPanel->activate();
if (curInt->isAutoFightOn)
{
bAutofight->activate();
return;
}
CIntObject::activate();
bOptions->activate();
bSurrender->activate();
bFlee->activate();
bAutofight->activate();
bSpell->activate();
bWait->activate();
bDefence->activate();
if (attackingHero)
attackingHero->activate();
@ -382,32 +343,14 @@ void CBattleInterface::activate()
if (settings["battle"]["showQueue"].Bool())
queue->activate();
if (tacticsMode)
{
btactNext->activate();
btactEnd->activate();
}
else
{
bConsoleUp->activate();
bConsoleDown->activate();
}
LOCPLINT->cingconsole->activate();
}
void CBattleInterface::deactivate()
{
controlPanel->deactivate();
CIntObject::deactivate();
bOptions->deactivate();
bSurrender->deactivate();
bFlee->deactivate();
bAutofight->deactivate();
bSpell->deactivate();
bWait->deactivate();
bDefence->deactivate();
fieldController->deactivate();
if (attackingHero)
@ -417,17 +360,6 @@ void CBattleInterface::deactivate()
if (settings["battle"]["showQueue"].Bool())
queue->deactivate();
if (tacticsMode)
{
btactNext->deactivate();
btactEnd->deactivate();
}
else
{
bConsoleUp->deactivate();
bConsoleDown->deactivate();
}
LOCPLINT->cingconsole->deactivate();
}
@ -468,189 +400,6 @@ void CBattleInterface::clickRight(tribool down, bool previousState)
}
}
void CBattleInterface::bOptionsf()
{
if (spellDestSelectMode) //we are casting a spell
return;
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
Rect tempRect = genRect(431, 481, 160, 84);
tempRect += pos.topLeft();
GH.pushIntT<CBattleOptionsWindow>(tempRect, this);
}
void CBattleInterface::bSurrenderf()
{
if(spellDestSelectMode) //we are casting a spell
return;
int cost = curInt->cb->battleGetSurrenderCost();
if(cost >= 0)
{
std::string enemyHeroName = curInt->cb->battleGetEnemyHero().name;
if(enemyHeroName.empty())
{
logGlobal->warn("Surrender performed without enemy hero, should not happen!");
enemyHeroName = "#ENEMY#";
}
std::string surrenderMessage = boost::str(boost::format(CGI->generaltexth->allTexts[32]) % enemyHeroName % cost); //%s states: "I will accept your surrender and grant you and your troops safe passage for the price of %d gold."
curInt->showYesNoDialog(surrenderMessage, [this](){ reallySurrender(); }, nullptr);
}
}
void CBattleInterface::bFleef()
{
if (spellDestSelectMode) //we are casting a spell
return;
if ( curInt->cb->battleCanFlee() )
{
CFunctionList<void()> ony = std::bind(&CBattleInterface::reallyFlee,this);
curInt->showYesNoDialog(CGI->generaltexth->allTexts[28], ony, nullptr); //Are you sure you want to retreat?
}
else
{
std::vector<std::shared_ptr<CComponent>> comps;
std::string heroName;
//calculating fleeing hero's name
if (attackingHeroInstance)
if (attackingHeroInstance->tempOwner == curInt->cb->getMyColor())
heroName = attackingHeroInstance->name;
if (defendingHeroInstance)
if (defendingHeroInstance->tempOwner == curInt->cb->getMyColor())
heroName = defendingHeroInstance->name;
//calculating text
auto txt = boost::format(CGI->generaltexth->allTexts[340]) % heroName; //The Shackles of War are present. %s can not retreat!
//printing message
curInt->showInfoDialog(boost::to_string(txt), comps);
}
}
void CBattleInterface::reallyFlee()
{
giveCommand(EActionType::RETREAT);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
void CBattleInterface::reallySurrender()
{
if (curInt->cb->getResourceAmount(Res::GOLD) < curInt->cb->battleGetSurrenderCost())
{
curInt->showInfoDialog(CGI->generaltexth->allTexts[29]); //You don't have enough gold!
}
else
{
giveCommand(EActionType::SURRENDER);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
}
void CBattleInterface::bAutofightf()
{
if(spellDestSelectMode) //we are casting a spell
return;
//Stop auto-fight mode
if(curInt->isAutoFightOn)
{
assert(curInt->autofightingAI);
curInt->isAutoFightOn = false;
logGlobal->trace("Stopping the autofight...");
}
else if(!curInt->autofightingAI)
{
curInt->isAutoFightOn = true;
blockUI(true);
auto ai = CDynLibHandler::getNewBattleAI(settings["server"]["friendlyAI"].String());
ai->init(curInt->env, curInt->cb);
ai->battleStart(army1, army2, int3(0,0,0), attackingHeroInstance, defendingHeroInstance, curInt->cb->battleGetMySide());
curInt->autofightingAI = ai;
curInt->cb->registerBattleInterface(ai);
requestAutofightingAIToTakeAction();
}
}
void CBattleInterface::bSpellf()
{
if (spellDestSelectMode) //we are casting a spell
return;
if (!myTurn)
return;
auto myHero = currentHero();
if(!myHero)
return;
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
ESpellCastProblem::ESpellCastProblem spellCastProblem = curInt->cb->battleCanCastSpell(myHero, spells::Mode::HERO);
if(spellCastProblem == ESpellCastProblem::OK)
{
GH.pushIntT<CSpellWindow>(myHero, curInt.get());
}
else if (spellCastProblem == ESpellCastProblem::MAGIC_IS_BLOCKED)
{
//TODO: move to spell mechanics, add more information to spell cast problem
//Handle Orb of Inhibition-like effects -> we want to display dialog with info, why casting is impossible
auto blockingBonus = currentHero()->getBonusLocalFirst(Selector::type()(Bonus::BLOCK_ALL_MAGIC));
if (!blockingBonus)
return;
if (blockingBonus->source == Bonus::ARTIFACT)
{
const int32_t artID = blockingBonus->sid;
//If we have artifact, put name of our hero. Otherwise assume it's the enemy.
//TODO check who *really* is source of bonus
std::string heroName = myHero->hasArt(artID) ? myHero->name : enemyHero().name;
//%s wields the %s, an ancient artifact which creates a p dead to all magic.
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[683])
% heroName % CGI->artifacts()->getByIndex(artID)->getName()));
}
}
}
void CBattleInterface::bWaitf()
{
if (spellDestSelectMode) //we are casting a spell
return;
if (activeStack != nullptr)
giveCommand(EActionType::WAIT);
}
void CBattleInterface::bDefencef()
{
if (spellDestSelectMode) //we are casting a spell
return;
if (activeStack != nullptr)
giveCommand(EActionType::DEFEND);
}
void CBattleInterface::bConsoleUpf()
{
if (spellDestSelectMode) //we are casting a spell
return;
console->scrollUp();
}
void CBattleInterface::bConsoleDownf()
{
if (spellDestSelectMode) //we are casting a spell
return;
console->scrollDown();
}
void CBattleInterface::unitAdded(const CStack * stack)
{
creDir[stack->ID] = stack->side == BattleSide::ATTACKER; // must be set before getting stack position
@ -784,7 +533,7 @@ void CBattleInterface::newRoundFirst( int round )
void CBattleInterface::newRound(int number)
{
console->addText(CGI->generaltexth->allTexts[412]);
controlPanel->console->addText(CGI->generaltexth->allTexts[412]);
}
void CBattleInterface::giveCommand(EActionType action, BattleHex tile, si32 additional)
@ -1050,7 +799,7 @@ void CBattleInterface::displayBattleLog(const std::vector<MetaString> & battleLo
{
std::string formatted = line.toString();
boost::algorithm::trim(formatted);
if(!console->addText(formatted))
if(!controlPanel->console->addText(formatted))
logGlobal->warn("Too long battle log line");
}
}
@ -1143,7 +892,7 @@ void CBattleInterface::battleTriggerEffect(const BattleTriggerEffect & bte)
boost::algorithm::replace_first(hlp,"%s",(stack->getName()));
displayEffect(20,stack->getPosition());
CCS->soundh->playSound(soundBase::GOODMRLE);
console->addText(hlp);
controlPanel->console->addText(hlp);
break;
}
default:
@ -1194,7 +943,7 @@ void CBattleInterface::setActiveStack(const CStack *stack)
if (activeStack) // update UI
creAnims[activeStack->ID]->setBorderColor(AnimationControls::getGoldBorder());
blockUI(activeStack == nullptr);
controlPanel->blockUI(activeStack == nullptr);
}
void CBattleInterface::setHoveredStack(const CStack *stack)
@ -1431,7 +1180,7 @@ void CBattleInterface::endAction(const BattleAction* action)
queue->update();
if (tacticsMode) //stack ended movement in tactics phase -> select the next one
bTacticNextStack(stack);
tacticNextStack(stack);
if(action->actionType == EActionType::HERO_SPELL) //we have activated next stack after sending request that has been just realized -> blockmap due to movement has changed
fieldController->redrawBackgroundWithHexes(activeStack);
@ -1439,12 +1188,12 @@ void CBattleInterface::endAction(const BattleAction* action)
if (activeStack && !animsAreDisplayed.get() && pendingAnims.empty() && !active)
{
logGlobal->warn("Something wrong... interface was deactivated but there is no animation. Reactivating...");
blockUI(false);
controlPanel->blockUI(false);
}
else
{
// block UI if no active stack (e.g. enemy turn);
blockUI(activeStack == nullptr);
controlPanel->blockUI(activeStack == nullptr);
}
}
@ -1476,58 +1225,15 @@ void CBattleInterface::showQueue()
}
}
void CBattleInterface::blockUI(bool on)
{
bool canCastSpells = false;
auto hero = curInt->cb->battleGetMyHero();
if(hero)
{
ESpellCastProblem::ESpellCastProblem spellcastingProblem = curInt->cb->battleCanCastSpell(hero, spells::Mode::HERO);
//if magic is blocked, we leave button active, so the message can be displayed after button click
canCastSpells = spellcastingProblem == ESpellCastProblem::OK || spellcastingProblem == ESpellCastProblem::MAGIC_IS_BLOCKED;
}
bool canWait = activeStack ? !activeStack->waitedThisTurn : false;
bOptions->block(on);
bFlee->block(on || !curInt->cb->battleCanFlee());
bSurrender->block(on || curInt->cb->battleGetSurrenderCost() < 0);
// block only if during enemy turn and auto-fight is off
// otherwise - crash on accessing non-exisiting active stack
bAutofight->block(!curInt->isAutoFightOn && !activeStack);
if (tacticsMode && btactEnd && btactNext)
{
btactNext->block(on);
btactEnd->block(on);
}
else
{
bConsoleUp->block(on);
bConsoleDown->block(on);
}
bSpell->block(on || tacticsMode || !canCastSpells);
bWait->block(on || tacticsMode || !canWait);
bDefence->block(on || tacticsMode);
}
void CBattleInterface::startAction(const BattleAction* action)
{
//setActiveStack(nullptr);
setHoveredStack(nullptr);
blockUI(true);
controlPanel->blockUI(true);
if(action->actionType == EActionType::END_TACTIC_PHASE)
{
SDL_FreeSurface(menu);
menu = BitmapHandler::loadBitmap("CBAR.bmp");
graphics->blueToPlayersAdv(menu, curInt->playerID);
controlPanel->tacticPhaseEnded();
return;
}
@ -1586,7 +1292,7 @@ void CBattleInterface::startAction(const BattleAction* action)
}
if(txtid != 0)
console->addText(stack->formatGeneralMessage(txtid));
controlPanel->console->addText(stack->formatGeneralMessage(txtid));
//displaying special abilities
switch(action->actionType)
@ -1604,10 +1310,10 @@ void CBattleInterface::waitForAnims()
animsAreDisplayed.waitWhileTrue();
}
void CBattleInterface::bEndTacticPhase()
void CBattleInterface::tacticPhaseEnd()
{
setActiveStack(nullptr);
blockUI(true);
controlPanel->blockUI(true);
tacticsMode = false;
}
@ -1616,7 +1322,7 @@ static bool immobile(const CStack *s)
return !s->Speed(0, true); //should bound stacks be immobile?
}
void CBattleInterface::bTacticNextStack(const CStack * current)
void CBattleInterface::tacticNextStack(const CStack * current)
{
if (!current)
current = activeStack;
@ -1628,7 +1334,7 @@ void CBattleInterface::bTacticNextStack(const CStack * current)
vstd::erase_if (stacksOfMine, &immobile);
if (stacksOfMine.empty())
{
bEndTacticPhase();
tacticPhaseEnd();
return;
}
@ -2099,8 +1805,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
{
if (setCursor)
CCS->curh->changeGraphic(cursorType, cursorFrame);
this->console->alterText(consoleMsg);
this->console->whoSetAlter = 0;
controlPanel->console->write(consoleMsg);
}
if (eventType == LCLICK && realizeAction)
{
@ -2112,7 +1817,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
realizeAction();
if (!secondaryTarget) //do not replace teleport or sacrifice cursor
CCS->curh->changeGraphic(ECursor::COMBAT, ECursor::COMBAT_POINTER);
this->console->alterText("");
controlPanel->console->clear();
}
}
}
@ -2215,7 +1920,7 @@ void CBattleInterface::requestAutofightingAIToTakeAction()
//TODO implement the possibility that the AI will be triggered for further actions
//TODO any solution to merge tactics phase & normal phase in the way it is handled by the player and battle interface?
setActiveStack(nullptr);
blockUI(true);
controlPanel->blockUI(true);
tacticsMode = false;
}
else
@ -2443,31 +2148,9 @@ void CBattleInterface::showBattleEffects(SDL_Surface *to, const std::vector<cons
void CBattleInterface::showInterface(SDL_Surface *to)
{
blitAt(menu, pos.x, 556 + pos.y, to);
if (tacticsMode)
{
btactNext->showAll(to);
btactEnd->showAll(to);
}
else
{
console->showAll(to);
bConsoleUp->showAll(to);
bConsoleDown->showAll(to);
}
//showing buttons
bOptions->showAll(to);
bSurrender->showAll(to);
bFlee->showAll(to);
bAutofight->showAll(to);
bSpell->showAll(to);
bWait->showAll(to);
bDefence->showAll(to);
//showing in-game console
LOCPLINT->cingconsole->show(to);
controlPanel->show(to);
Rect posWithQueue = Rect(pos.x, pos.y, 800, 600);
@ -2594,7 +2277,7 @@ void CBattleInterface::updateBattleAnimations()
if (preSize > 0 && pendingAnims.empty())
{
//anims ended
blockUI(activeStack == nullptr);
controlPanel->blockUI(activeStack == nullptr);
animsAreDisplayed.setn(false);
}

View File

@ -62,6 +62,7 @@ class CBattleProjectileController;
class CBattleSiegeController;
class CBattleObstacleController;
class CBattleFieldController;
class CBattleControlPanel;
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct StackAttackedInfo
@ -118,24 +119,12 @@ enum class MouseHoveredHexContext
class CBattleInterface : public WindowBase
{
private:
SDL_Surface *menu, *amountNormal, *amountNegative, *amountPositive, *amountEffNeutral;
SDL_Surface *amountNormal, *amountNegative, *amountPositive, *amountEffNeutral;
std::shared_ptr<CButton> bOptions;
std::shared_ptr<CButton> bSurrender;
std::shared_ptr<CButton> bFlee;
std::shared_ptr<CButton> bAutofight;
std::shared_ptr<CButton> bSpell;
std::shared_ptr<CButton> bWait;
std::shared_ptr<CButton> bDefence;
std::shared_ptr<CButton> bConsoleUp;
std::shared_ptr<CButton> bConsoleDown;
std::shared_ptr<CButton> btactNext;
std::shared_ptr<CButton> btactEnd;
std::shared_ptr<CBattleConsole> console;
std::shared_ptr<CBattleHero> attackingHero;
std::shared_ptr<CBattleHero> defendingHero;
std::shared_ptr<CStackQueue> queue;
std::shared_ptr<CBattleControlPanel> controlPanel;
const CCreatureSet *army1, *army2; //copy of initial armies (for result window)
const CGHeroInstance *attackingHeroInstance, *defendingHeroInstance;
@ -236,25 +225,9 @@ public:
const BattleResult *bresult; //result of a battle; if non-zero then display when all animations end
// block all UI elements, e.g. during enemy turn
// unlike activate/deactivate this method will correctly grey-out all elements
void blockUI(bool on);
void tacticNextStack(const CStack *current);
void tacticPhaseEnd();
//button handle funcs:
void bOptionsf();
void bSurrenderf();
void bFleef();
void reallyFlee(); //performs fleeing without asking player
void reallySurrender(); //performs surrendering without asking player
void bAutofightf();
void bSpellf();
void bWaitf();
void bDefencef();
void bConsoleUpf();
void bConsoleDownf();
void bTacticNextStack(const CStack *current = nullptr);
void bEndTacticPhase();
//end of button handle funcs
//napisz tu klase odpowiadajaca za wyswietlanie bitwy i obsluge uzytkownika, polecenia ma przekazywac callbackiem
void activate() override;
void deactivate() override;
@ -332,4 +305,5 @@ public:
friend class CBattleSiegeController;
friend class CBattleObstacleController;
friend class CBattleFieldController;
friend class CBattleControlPanel;
};

View File

@ -13,6 +13,7 @@
#include "CBattleInterface.h"
#include "CBattleSiegeController.h"
#include "CBattleFieldController.h"
#include "CBattleControlPanel.h"
#include "../CBitmapHandler.h"
#include "../CGameInfo.h"
@ -50,10 +51,6 @@ void CBattleConsole::showAll(SDL_Surface * to)
{
graphics->fonts[FONT_SMALL]->renderTextLinesCenter(to, CMessage::breakText(ingcAlter, pos.w, FONT_SMALL), Colors::WHITE, textPos);
}
else if(alterTxt.size())
{
graphics->fonts[FONT_SMALL]->renderTextLinesCenter(to, CMessage::breakText(alterTxt, pos.w, FONT_SMALL), Colors::WHITE, textPos);
}
else if(texts.size())
{
if(texts.size()==1)
@ -88,32 +85,6 @@ bool CBattleConsole::addText(const std::string & text)
lastShown = (int)texts.size()-1;
return true;
}
void CBattleConsole::alterText(const std::string &text)
{
//char buf[500];
//sprintf(buf, text.c_str());
//alterTxt = buf;
alterTxt = text;
}
void CBattleConsole::eraseText(ui32 pos)
{
if(pos < texts.size())
{
texts.erase(texts.begin() + pos);
if(lastShown == texts.size())
--lastShown;
}
}
void CBattleConsole::changeTextAt(const std::string & text, ui32 pos)
{
if(pos >= texts.size()) //no such pos
return;
texts[pos] = text;
}
void CBattleConsole::scrollUp(ui32 by)
{
if(lastShown > static_cast<int>(by))
@ -126,8 +97,31 @@ void CBattleConsole::scrollDown(ui32 by)
lastShown += by;
}
CBattleConsole::CBattleConsole() : lastShown(-1), alterTxt(""), whoSetAlter(0)
{}
CBattleConsole::CBattleConsole(const Rect & position) : lastShown(-1)
{
pos = position;
}
void CBattleConsole::clearMatching(const std::string & Text)
{
if (ingcAlter == Text)
clear();
}
void CBattleConsole::clear()
{
ingcAlter.clear();
}
void CBattleConsole::write(const std::string & Text)
{
ingcAlter = Text;
}
void CBattleConsole::lock(bool shouldLock)
{
// no-op?
}
void CBattleHero::show(SDL_Surface * to)
{
@ -627,7 +621,7 @@ void CClickableHex::hover(bool on)
//Hoverable::hover(on);
if(!on && setAlterText)
{
myInterface->console->alterTxt = std::string();
myInterface->controlPanel->console->clear();
setAlterText = false;
}
}
@ -644,20 +638,20 @@ void CClickableHex::mouseMoved(const SDL_MouseMotionEvent &sEvent)
if(hovered && strictHovered) //print attacked creature to console
{
const CStack * attackedStack = myInterface->getCurrentPlayerInterface()->cb->battleGetStackByPos(myNumber);
if(myInterface->console->alterTxt.size() == 0 &&attackedStack != nullptr &&
if( attackedStack != nullptr &&
attackedStack->owner != myInterface->getCurrentPlayerInterface()->playerID &&
attackedStack->alive())
{
MetaString text;
text.addTxt(MetaString::GENERAL_TXT, 220);
attackedStack->addNameReplacement(text);
myInterface->console->alterTxt = text.toString();
myInterface->controlPanel->console->write(text.toString());
setAlterText = true;
}
}
else if(setAlterText)
{
myInterface->console->alterTxt = std::string();
myInterface->controlPanel->console->clear();
setAlterText = false;
}
}

View File

@ -39,23 +39,26 @@ class CAnimImage;
class CPlayerInterface;
/// Class which shows the console at the bottom of the battle screen and manages the text of the console
class CBattleConsole : public CIntObject
class CBattleConsole : public CIntObject, public IStatusBar
{
private:
std::vector< std::string > texts; //a place where texts are stored
int lastShown; //last shown line of text
public:
std::string alterTxt; //if it's not empty, this text is displayed
std::string ingcAlter; //alternative text set by in-game console - very important!
int whoSetAlter; //who set alter text; 0 - battle interface or none, 1 - button
CBattleConsole();
public:
CBattleConsole(const Rect & position);
void showAll(SDL_Surface * to = 0) override;
bool addText(const std::string &text); //adds text at the last position; returns false if failed (e.g. text longer than 70 characters)
void alterText(const std::string &text); //place string at alterTxt
void eraseText(ui32 pos); //erases added text at position pos
void changeTextAt(const std::string &text, ui32 pos); //if we have more than pos texts, pos-th is changed to given one
void scrollUp(ui32 by = 1); //scrolls console up by 'by' positions
void scrollDown(ui32 by = 1); //scrolls console up by 'by' positions
void clearMatching(const std::string & Text) override;
void clear() override;
void write(const std::string & Text) override;
void lock(bool shouldLock) override;
};
/// Hero battle animation

View File

@ -20,7 +20,7 @@ template <typename T> struct CondSh;
VCMI_LIB_NAMESPACE_END
class CFramerateManager;
class CGStatusBar;
class IStatusBar;
class CIntObject;
class IUpdateable;
class IShowActivatable;
@ -65,7 +65,7 @@ class CGuiHandler
public:
CFramerateManager * mainFPSmng; //to keep const framerate
std::list<std::shared_ptr<IShowActivatable>> listInt; //list of interfaces - front=foreground; back = background (includes adventure map, window interfaces, all kind of active dialogs, and so on)
std::shared_ptr<CGStatusBar> statusbar;
std::shared_ptr<IStatusBar> statusbar;
private:
std::vector<std::shared_ptr<IShowActivatable>> disposed;

View File

@ -373,3 +373,6 @@ void WindowBase::close()
logGlobal->error("Only top interface must be closed");
GH.popInts(1);
}
IStatusBar::~IStatusBar()
{}

View File

@ -217,3 +217,13 @@ public:
protected:
void close();
};
class IStatusBar
{
public:
virtual ~IStatusBar();
virtual void clear() = 0;
virtual void clearMatching(const std::string & Text) = 0;
virtual void write(const std::string & Text) = 0;
virtual void lock(bool shouldLock) = 0;
};

View File

@ -87,7 +87,7 @@ void CList::CListItem::clickLeft(tribool down, bool previousState)
void CList::CListItem::hover(bool on)
{
if (on)
GH.statusbar->setText(getHoverText());
GH.statusbar->write(getHoverText());
else
GH.statusbar->clear();
}
@ -572,7 +572,7 @@ void CMinimap::clickRight(tribool down, bool previousState)
void CMinimap::hover(bool on)
{
if(on)
GH.statusbar->setText(CGI->generaltexth->zelp[291].first);
GH.statusbar->write(CGI->generaltexth->zelp[291].first);
else
GH.statusbar->clear();
}
@ -876,7 +876,7 @@ void CInfoBar::clickRight(tribool down, bool previousState)
void CInfoBar::hover(bool on)
{
if(on)
GH.statusbar->setText(CGI->generaltexth->zelp[292].first);
GH.statusbar->write(CGI->generaltexth->zelp[292].first);
else
GH.statusbar->clear();
}
@ -1129,20 +1129,17 @@ void CInGameConsole::textEdited(const SDL_TextEditingEvent & event)
void CInGameConsole::startEnteringText()
{
CSDL_Ext::startTextInput(&GH.statusbar->pos);
auto * statusBar = dynamic_cast<CGStatusBar*>(GH.statusbar.get());
enteredText = "_";
if(GH.topInt() == adventureInt)
if (statusBar)
{
GH.statusbar->alignment = TOPLEFT;
GH.statusbar->setText(enteredText);
CSDL_Ext::startTextInput(&statusBar->pos);
//Prevent changes to the text from mouse interaction with the adventure map
GH.statusbar->lock(true);
}
else if(LOCPLINT->battleInt)
{
LOCPLINT->battleInt->console->ingcAlter = enteredText;
enteredText = "_";
statusBar->alignment = TOPLEFT;
statusBar->write(enteredText);
statusBar->lock(true);
}
}
@ -1159,31 +1156,23 @@ void CInGameConsole::endEnteringText(bool printEnteredText)
//print(txt);
}
enteredText.clear();
if(GH.topInt() == adventureInt)
auto * statusBar = dynamic_cast<CGStatusBar*>(GH.statusbar.get());
if(statusBar)
{
GH.statusbar->alignment = CENTER;
GH.statusbar->lock(false);
GH.statusbar->clear();
}
else if(LOCPLINT->battleInt)
{
LOCPLINT->battleInt->console->ingcAlter = "";
statusBar->alignment = CENTER;
}
GH.statusbar->lock(false);
GH.statusbar->clear();
}
void CInGameConsole::refreshEnteredText()
{
if(GH.topInt() == adventureInt)
{
GH.statusbar->lock(false);
GH.statusbar->clear();
GH.statusbar->setText(enteredText);
GH.statusbar->lock(true);
}
else if(LOCPLINT->battleInt)
{
LOCPLINT->battleInt->console->ingcAlter = enteredText;
}
GH.statusbar->lock(false);
GH.statusbar->clear();
GH.statusbar->write(enteredText);
GH.statusbar->lock(true);
}
CAdvMapPanel::CAdvMapPanel(SDL_Surface * bg, Point position)

View File

@ -207,26 +207,10 @@ void CButton::hover (bool on)
if(!name.empty() && !isBlocked()) //if there is no name, there is nothing to display also
{
if (LOCPLINT && LOCPLINT->battleInt) //for battle buttons
{
if(on && LOCPLINT->battleInt->console->alterTxt == "")
{
LOCPLINT->battleInt->console->alterTxt = name;
LOCPLINT->battleInt->console->whoSetAlter = 1;
}
else if (LOCPLINT->battleInt->console->alterTxt == name)
{
LOCPLINT->battleInt->console->alterTxt = "";
LOCPLINT->battleInt->console->whoSetAlter = 0;
}
}
else if(GH.statusbar) //for other buttons
{
if (on)
GH.statusbar->setText(name);
else if ( GH.statusbar->getText()==(name) )
GH.statusbar->clear();
}
if (on)
GH.statusbar->write(name);
else
GH.statusbar->clearMatching(name);
}
}
@ -530,7 +514,7 @@ void CVolumeSlider::clickRight(tribool down, bool previousState)
if(!helpBox.empty())
CRClickPopup::createAndPush(helpBox);
if(GH.statusbar)
GH.statusbar->setText(helpBox);
GH.statusbar->write(helpBox);
}
}

View File

@ -118,7 +118,7 @@ void CGarrisonSlot::hover (bool on)
temp = CGI->generaltexth->tcommands[11]; //Empty
}
}
GH.statusbar->setText(temp);
GH.statusbar->write(temp);
}
else
{

View File

@ -34,9 +34,9 @@
void CHoverableArea::hover (bool on)
{
if (on)
GH.statusbar->setText(hoverText);
else if (GH.statusbar->getText()==hoverText)
GH.statusbar->clear();
GH.statusbar->write(hoverText);
else
GH.statusbar->clearMatching(hoverText);
}
CHoverableArea::CHoverableArea()
@ -150,7 +150,7 @@ void CHeroArea::clickRight(tribool down, bool previousState)
void CHeroArea::hover(bool on)
{
if (on && hero)
GH.statusbar->setText(hero->getObjectName());
GH.statusbar->write(hero->getObjectName());
else
GH.statusbar->clear();
}

View File

@ -339,12 +339,18 @@ void CTextBox::setText(const std::string & text)
}
}
void CGStatusBar::setText(const std::string & Text)
void CGStatusBar::write(const std::string & Text)
{
if(!textLock)
CLabel::setText(Text);
}
void CGStatusBar::clearMatching(const std::string & Text)
{
if (getText() == Text)
clear();
}
void CGStatusBar::clear()
{
setText("");

View File

@ -114,7 +114,7 @@ public:
};
/// Status bar which is shown at the bottom of the in-game screens
class CGStatusBar : public CLabel, public std::enable_shared_from_this<CGStatusBar>
class CGStatusBar : public CLabel, public std::enable_shared_from_this<CGStatusBar>, public IStatusBar
{
bool textLock; //Used for blocking changes to the text
void init();
@ -132,12 +132,14 @@ public:
ret->init();
return ret;
}
void clear();//clears statusbar and refreshes
void setText(const std::string & Text) override; //prints text and refreshes statusbar
void clearMatching(const std::string & Text) override;
void clear() override;//clears statusbar and refreshes
void write(const std::string & Text) override; //prints text and refreshes statusbar
void show(SDL_Surface * to) override; //shows statusbar (with current text)
void lock(bool shouldLock); //If true, current text cannot be changed until lock(false) is called
void lock(bool shouldLock) override; //If true, current text cannot be changed until lock(false) is called
};
class CFocusable;

View File

@ -261,7 +261,7 @@ void CBuildingRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
|| (*parent->selectedBuilding)<(*this)) //or we are on top
{
parent->selectedBuilding = this;
GH.statusbar->setText(getSubtitle());
GH.statusbar->write(getSubtitle());
}
}
}
@ -379,7 +379,7 @@ void CHeroGSlot::hover(bool on)
}
}
if(temp.size())
GH.statusbar->setText(temp);
GH.statusbar->write(temp);
}
void CHeroGSlot::clickLeft(tribool down, bool previousState)
@ -1031,11 +1031,11 @@ void CCreaInfo::hover(bool on)
if(on)
{
GH.statusbar->setText(message);
GH.statusbar->write(message);
}
else if (message == GH.statusbar->getText())
else
{
GH.statusbar->clear();
GH.statusbar->clearMatching(message);
}
}
@ -1105,7 +1105,7 @@ void CTownInfo::hover(bool on)
if(on)
{
if(building )
GH.statusbar->setText(building->Name());
GH.statusbar->write(building->Name());
}
else
{
@ -1326,7 +1326,7 @@ void CHallInterface::CBuildingBox::hover(bool on)
else
toPrint = CGI->generaltexth->hcommands[state];
boost::algorithm::replace_first(toPrint,"%s",building->Name());
GH.statusbar->setText(toPrint);
GH.statusbar->write(toPrint);
}
else
{
@ -1515,7 +1515,7 @@ void LabeledValue::hover(bool on)
{
if(on)
{
GH.statusbar->setText(hoverText);
GH.statusbar->write(hoverText);
}
else
{
@ -1683,7 +1683,7 @@ const CBuilding * CFortScreen::RecruitArea::getMyBuilding()
void CFortScreen::RecruitArea::hover(bool on)
{
if(on)
GH.statusbar->setText(hoverText);
GH.statusbar->write(hoverText);
else
GH.statusbar->clear();
}
@ -1774,7 +1774,7 @@ void CMageGuildScreen::Scroll::clickRight(tribool down, bool previousState)
void CMageGuildScreen::Scroll::hover(bool on)
{
if(on)
GH.statusbar->setText(spell->name);
GH.statusbar->write(spell->name);
else
GH.statusbar->clear();

View File

@ -244,13 +244,13 @@ void CTradeWindow::CTradeableItem::hover(bool on)
{
case CREATURE:
case CREATURE_PLACEHOLDER:
GH.statusbar->setText(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->namePl));
GH.statusbar->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->namePl));
break;
case ARTIFACT_PLACEHOLDER:
if(id < 0)
GH.statusbar->setText(CGI->generaltexth->zelp[582].first);
GH.statusbar->write(CGI->generaltexth->zelp[582].first);
else
GH.statusbar->setText(CGI->artifacts()->getByIndex(id)->getName());
GH.statusbar->write(CGI->artifacts()->getByIndex(id)->getName());
break;
}
}

View File

@ -799,7 +799,7 @@ void CTavernWindow::HeroPortrait::hover(bool on)
{
//Hoverable::hover(on);
if(on)
GH.statusbar->setText(hoverName);
GH.statusbar->write(hoverName);
else
GH.statusbar->clear();
}
@ -1550,7 +1550,7 @@ void CUniversityWindow::CItem::clickRight(tribool down, bool previousState)
void CUniversityWindow::CItem::hover(bool on)
{
if(on)
GH.statusbar->setText(CGI->skillh->skillName(ID));
GH.statusbar->write(CGI->skillh->skillName(ID));
else
GH.statusbar->clear();
}