2022-11-18 17:54:10 +02:00
/*
2022-12-21 17:06:47 +02:00
* BattleWindow . cpp , part of VCMI engine
2022-11-18 17:54:10 +02:00
*
* 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"
2022-12-21 17:06:47 +02:00
# include "BattleWindow.h"
2022-11-28 16:43:38 +02:00
2022-12-09 13:38:46 +02:00
# include "BattleInterface.h"
# include "BattleInterfaceClasses.h"
2022-12-21 17:02:53 +02:00
# include "BattleFieldController.h"
2022-12-09 13:38:46 +02:00
# include "BattleStacksController.h"
# include "BattleActionsController.h"
2022-11-28 16:43:38 +02:00
2022-11-18 17:54:10 +02:00
# include "../CGameInfo.h"
# include "../CPlayerInterface.h"
2022-12-21 17:02:53 +02:00
# include "../CMusicHandler.h"
2023-01-05 19:34:37 +02:00
# include "../gui/CursorHandler.h"
2022-11-18 17:54:10 +02:00
# include "../gui/CGuiHandler.h"
2023-04-27 19:21:06 +02:00
# include "../gui/Shortcut.h"
2023-05-16 14:10:26 +02:00
# include "../gui/WindowHandler.h"
2022-11-18 17:54:10 +02:00
# include "../windows/CSpellWindow.h"
2022-11-28 16:43:38 +02:00
# include "../widgets/Buttons.h"
# include "../widgets/Images.h"
2023-02-01 20:42:06 +02:00
# include "../windows/CMessage.h"
# include "../render/CAnimation.h"
# include "../render/Canvas.h"
# include "../adventureMap/CInGameConsole.h"
2022-11-28 16:43:38 +02:00
# include "../../CCallback.h"
# include "../../lib/CGeneralTextHandler.h"
2023-06-23 17:02:48 +02:00
# include "../../lib/gameState/InfoAboutArmy.h"
2022-11-28 16:43:38 +02:00
# include "../../lib/mapObjects/CGHeroInstance.h"
2022-11-18 17:54:10 +02:00
# include "../../lib/CStack.h"
# include "../../lib/CConfigHandler.h"
2022-12-25 12:22:07 +02:00
# include "../../lib/filesystem/ResourceID.h"
2023-02-18 18:58:22 +02:00
# include "../windows/settings/SettingsMainWindow.h"
2022-11-18 17:54:10 +02:00
2022-12-21 17:06:47 +02:00
BattleWindow : : BattleWindow ( BattleInterface & owner ) :
2023-03-25 00:48:14 +02:00
owner ( owner ) ,
defaultAction ( PossiblePlayerBattleAction : : INVALID )
2022-11-18 17:54:10 +02:00
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE ;
2022-12-21 17:02:53 +02:00
pos . w = 800 ;
pos . h = 600 ;
pos = center ( ) ;
2023-01-04 16:20:53 +02:00
REGISTER_BUILDER ( " battleConsole " , & BattleWindow : : buildBattleConsole ) ;
2022-12-25 12:22:07 +02:00
2023-01-04 16:20:53 +02:00
const JsonNode config ( ResourceID ( " config/widgets/BattleWindow.json " ) ) ;
2022-12-25 12:22:07 +02:00
2023-04-29 12:48:21 +02:00
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 ) ) ;
addShortcut ( EShortcut : : BATTLE_AUTOCOMBAT , std : : bind ( & BattleWindow : : bAutofightf , this ) ) ;
addShortcut ( EShortcut : : BATTLE_CAST_SPELL , std : : bind ( & BattleWindow : : bSpellf , this ) ) ;
addShortcut ( EShortcut : : BATTLE_WAIT , std : : bind ( & BattleWindow : : bWaitf , this ) ) ;
addShortcut ( EShortcut : : BATTLE_DEFEND , std : : bind ( & BattleWindow : : bDefencef , this ) ) ;
addShortcut ( EShortcut : : BATTLE_CONSOLE_UP , std : : bind ( & BattleWindow : : bConsoleUpf , this ) ) ;
addShortcut ( EShortcut : : BATTLE_CONSOLE_DOWN , std : : bind ( & BattleWindow : : bConsoleDownf , this ) ) ;
addShortcut ( EShortcut : : BATTLE_TACTICS_NEXT , std : : bind ( & BattleWindow : : bTacticNextStack , this ) ) ;
addShortcut ( EShortcut : : BATTLE_TACTICS_END , std : : bind ( & BattleWindow : : bTacticPhaseEnd , this ) ) ;
addShortcut ( EShortcut : : BATTLE_SELECT_ACTION , std : : bind ( & BattleWindow : : bSwitchActionf , this ) ) ;
addShortcut ( EShortcut : : BATTLE_TOGGLE_QUEUE , [ this ] ( ) { this - > toggleQueueVisibility ( ) ; } ) ;
2023-07-17 23:25:16 +02:00
addShortcut ( EShortcut : : BATTLE_TOGGLE_HEROES_STATS , [ this ] ( ) { this - > toggleStickyHeroWindowsVisibility ( ) ; } ) ;
2023-04-29 12:48:21 +02:00
addShortcut ( EShortcut : : BATTLE_USE_CREATURE_SPELL , [ this ] ( ) { this - > owner . actionsController - > enterCreatureCastingMode ( ) ; } ) ;
addShortcut ( EShortcut : : GLOBAL_CANCEL , [ this ] ( ) { this - > owner . actionsController - > endCastingSpell ( ) ; } ) ;
2022-12-25 12:22:07 +02:00
build ( config ) ;
console = widget < BattleConsole > ( " console " ) ;
2023-01-04 16:20:53 +02:00
2022-12-21 17:02:53 +02:00
owner . console = console ;
owner . fieldController . reset ( new BattleFieldController ( owner ) ) ;
owner . fieldController - > createHeroes ( ) ;
2023-03-05 16:36:28 +02:00
createQueue ( ) ;
2023-07-17 23:25:16 +02:00
createStickyHeroInfoWindows ( ) ;
2023-03-05 16:36:28 +02:00
if ( owner . tacticsMode )
tacticPhaseStarted ( ) ;
else
tacticPhaseEnded ( ) ;
2023-07-15 21:18:04 +02:00
addUsedEvents ( LCLICK | KEYBOARD ) ;
2023-03-05 16:36:28 +02:00
}
void BattleWindow : : createQueue ( )
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE ;
2022-12-21 17:02:53 +02:00
//create stack queue and adjust our own position
bool embedQueue ;
2023-04-05 17:36:10 +02:00
bool showQueue = settings [ " battle " ] [ " showQueue " ] . Bool ( ) ;
2022-12-21 17:02:53 +02:00
std : : string queueSize = settings [ " battle " ] [ " queueSize " ] . String ( ) ;
if ( queueSize = = " auto " )
2023-02-03 18:23:53 +02:00
embedQueue = GH . screenDimensions ( ) . y < 700 ;
2022-12-21 17:02:53 +02:00
else
2023-02-03 18:23:53 +02:00
embedQueue = GH . screenDimensions ( ) . y < 700 | | queueSize = = " small " ;
2022-12-21 17:02:53 +02:00
queue = std : : make_shared < StackQueue > ( embedQueue , owner ) ;
2023-04-05 17:36:10 +02:00
if ( ! embedQueue & & showQueue )
2022-12-21 17:02:53 +02:00
{
//re-center, taking into account stack queue position
pos . y - = queue - > pos . h ;
pos . h + = queue - > pos . h ;
pos = center ( ) ;
}
2023-04-05 17:36:10 +02:00
if ( ! showQueue )
queue - > disable ( ) ;
2022-11-18 17:54:10 +02:00
}
2023-07-17 23:25:16 +02:00
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 < HeroInfoBasicPanel > ( 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 < HeroInfoBasicPanel > ( info , & position ) ;
}
bool showInfoWindows = settings [ " battle " ] [ " stickyHeroInfoWindows " ] . Bool ( ) ;
if ( ! showInfoWindows )
{
if ( attackerHeroWindow )
attackerHeroWindow - > disable ( ) ;
if ( defenderHeroWindow )
defenderHeroWindow - > disable ( ) ;
}
}
2022-12-21 18:04:19 +02:00
BattleWindow : : ~ BattleWindow ( )
{
CPlayerInterface : : battleInt = nullptr ;
}
2023-01-04 16:20:53 +02:00
std : : shared_ptr < BattleConsole > BattleWindow : : buildBattleConsole ( const JsonNode & config ) const
2022-11-27 02:26:02 +02:00
{
2023-01-04 16:20:53 +02:00
auto rect = readRect ( config [ " rect " ] ) ;
auto offset = readPosition ( config [ " imagePosition " ] ) ;
auto background = widget < CPicture > ( " menuBattle " ) ;
return std : : make_shared < BattleConsole > ( background , rect . topLeft ( ) , offset , rect . dimensions ( ) ) ;
2022-11-27 02:26:02 +02:00
}
2023-02-15 23:38:41 +02:00
void BattleWindow : : toggleQueueVisibility ( )
{
if ( settings [ " battle " ] [ " showQueue " ] . Bool ( ) )
hideQueue ( ) ;
else
showQueue ( ) ;
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : hideQueue ( )
2022-11-27 02:26:02 +02:00
{
2023-02-15 23:38:41 +02:00
if ( settings [ " battle " ] [ " showQueue " ] . Bool ( ) = = false )
return ;
2022-12-21 17:02:53 +02:00
Settings showQueue = settings . write [ " battle " ] [ " showQueue " ] ;
showQueue - > Bool ( ) = false ;
queue - > disable ( ) ;
if ( ! queue - > embedded )
{
2023-01-04 16:40:38 +02:00
//re-center, taking into account stack queue position
pos . y + = queue - > pos . h ;
pos . h - = queue - > pos . h ;
pos = center ( ) ;
2022-12-21 17:02:53 +02:00
}
2023-05-16 14:10:26 +02:00
GH . windows ( ) . totalRedraw ( ) ;
2022-11-27 02:26:02 +02:00
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : showQueue ( )
2022-11-27 02:26:02 +02:00
{
2023-02-15 23:38:41 +02:00
if ( settings [ " battle " ] [ " showQueue " ] . Bool ( ) = = true )
return ;
2022-12-21 17:02:53 +02:00
Settings showQueue = settings . write [ " battle " ] [ " showQueue " ] ;
showQueue - > Bool ( ) = true ;
2023-03-05 16:36:28 +02:00
createQueue ( ) ;
updateQueue ( ) ;
2023-05-16 14:10:26 +02:00
GH . windows ( ) . totalRedraw ( ) ;
2022-12-21 17:02:53 +02:00
}
2023-07-17 23:25:16 +02:00
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 ;
2023-07-22 15:32:00 +02:00
Settings showStickyHeroInfoWindows = settings . write [ " battle " ] [ " stickyHeroInfoWindows " ] ;
showStickyHeroInfoWindows - > Bool ( ) = true ;
2023-07-17 23:25:16 +02:00
createStickyHeroInfoWindows ( ) ;
GH . windows ( ) . totalRedraw ( ) ;
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : updateQueue ( )
2022-12-21 17:02:53 +02:00
{
queue - > update ( ) ;
}
2023-07-22 15:32:00 +02:00
void BattleWindow : : updateHeroInfoWindow ( uint8_t side , const InfoAboutHero & hero )
{
std : : shared_ptr < HeroInfoBasicPanel > panelToUpdate = side = = 0 ? attackerHeroWindow : defenderHeroWindow ;
panelToUpdate - > update ( hero ) ;
}
2023-07-22 21:51:14 +02:00
void BattleWindow : : heroManaPointsChanged ( const CGHeroInstance * hero )
{
if ( hero = = owner . attackingHeroInstance | | hero = = owner . defendingHeroInstance )
{
InfoAboutHero heroInfo = InfoAboutHero ( ) ;
heroInfo . initFromHero ( hero , InfoAboutHero : : INBATTLE ) ;
updateHeroInfoWindow ( hero = = owner . attackingHeroInstance ? 0 : 1 , heroInfo ) ;
}
else
{
logGlobal - > error ( " BattleWindow::heroManaPointsChanged: 'Mana points changed' called for hero not belonging to current battle window " ) ;
}
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : activate ( )
2022-12-21 17:02:53 +02:00
{
2023-05-16 17:34:23 +02:00
GH . setStatusbar ( console ) ;
2022-12-21 17:02:53 +02:00
CIntObject : : activate ( ) ;
LOCPLINT - > cingconsole - > activate ( ) ;
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : deactivate ( )
2022-12-21 17:02:53 +02:00
{
2023-05-16 17:34:23 +02:00
GH . setStatusbar ( nullptr ) ;
2022-12-21 17:02:53 +02:00
CIntObject : : deactivate ( ) ;
LOCPLINT - > cingconsole - > deactivate ( ) ;
}
2023-05-07 19:03:57 +02:00
bool BattleWindow : : captureThisKey ( EShortcut key )
{
return owner . openingPlaying ( ) ;
}
2023-04-27 19:21:06 +02:00
void BattleWindow : : keyPressed ( EShortcut key )
2022-12-21 17:02:53 +02:00
{
2023-03-20 19:43:37 +02:00
if ( owner . openingPlaying ( ) )
2023-03-19 01:40:31 +02:00
{
2023-03-21 00:56:07 +02:00
owner . openingEnd ( ) ;
2023-03-19 01:40:31 +02:00
return ;
}
2023-04-29 12:48:21 +02:00
InterfaceObjectConfigurable : : keyPressed ( key ) ;
2022-11-27 02:26:02 +02:00
}
2023-07-15 21:18:04 +02:00
void BattleWindow : : clickPressed ( const Point & cursorPosition )
{
if ( owner . openingPlaying ( ) )
{
owner . openingEnd ( ) ;
return ;
}
InterfaceObjectConfigurable : : clickPressed ( cursorPosition ) ;
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : tacticPhaseStarted ( )
2022-11-18 17:54:10 +02:00
{
2023-01-04 16:20:53 +02:00
auto menuBattle = widget < CIntObject > ( " menuBattle " ) ;
auto console = widget < CIntObject > ( " console " ) ;
auto menuTactics = widget < CIntObject > ( " menuTactics " ) ;
auto tacticNext = widget < CIntObject > ( " tacticNext " ) ;
auto tacticEnd = widget < CIntObject > ( " tacticEnd " ) ;
2023-04-05 17:36:10 +02:00
auto alternativeAction = widget < CIntObject > ( " alternativeAction " ) ;
2023-01-04 16:20:53 +02:00
2022-12-21 17:02:53 +02:00
menuBattle - > disable ( ) ;
console - > disable ( ) ;
2023-04-05 17:36:10 +02:00
if ( alternativeAction )
alternativeAction - > disable ( ) ;
2022-11-18 17:54:10 +02:00
2022-12-21 17:02:53 +02:00
menuTactics - > enable ( ) ;
2023-01-04 16:20:53 +02:00
tacticNext - > enable ( ) ;
tacticEnd - > enable ( ) ;
2023-01-09 17:25:49 +02:00
redraw ( ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:02:53 +02:00
2022-12-21 17:06:47 +02:00
void BattleWindow : : tacticPhaseEnded ( )
2022-11-18 17:54:10 +02:00
{
2023-01-04 16:20:53 +02:00
auto menuBattle = widget < CIntObject > ( " menuBattle " ) ;
auto console = widget < CIntObject > ( " console " ) ;
auto menuTactics = widget < CIntObject > ( " menuTactics " ) ;
auto tacticNext = widget < CIntObject > ( " tacticNext " ) ;
auto tacticEnd = widget < CIntObject > ( " tacticEnd " ) ;
2023-04-05 17:36:10 +02:00
auto alternativeAction = widget < CIntObject > ( " alternativeAction " ) ;
2023-01-04 16:20:53 +02:00
2022-12-21 17:02:53 +02:00
menuBattle - > enable ( ) ;
console - > enable ( ) ;
2023-04-05 17:36:10 +02:00
if ( alternativeAction )
alternativeAction - > enable ( ) ;
2022-11-20 22:56:42 +02:00
2022-12-21 17:02:53 +02:00
menuTactics - > disable ( ) ;
2023-01-04 16:20:53 +02:00
tacticNext - > disable ( ) ;
tacticEnd - > disable ( ) ;
2023-01-09 17:25:49 +02:00
redraw ( ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bOptionsf ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
2022-12-18 22:32:07 +02:00
CCS - > curh - > set ( Cursor : : Map : : POINTER ) ;
2022-11-18 17:54:10 +02:00
2023-05-16 15:20:35 +02:00
GH . windows ( ) . createAndPushWindow < SettingsMainWindow > ( & owner ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bSurrenderf ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
2022-12-13 13:58:16 +02:00
int cost = owner . curInt - > cb - > battleGetSurrenderCost ( ) ;
2022-11-18 17:54:10 +02:00
if ( cost > = 0 )
{
2022-12-13 13:58:16 +02:00
std : : string enemyHeroName = owner . curInt - > cb - > battleGetEnemyHero ( ) . name ;
2022-11-18 17:54:10 +02:00
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."
2022-12-13 13:58:16 +02:00
owner . curInt - > showYesNoDialog ( surrenderMessage , [ this ] ( ) { reallySurrender ( ) ; } , nullptr ) ;
2022-11-18 17:54:10 +02:00
}
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bFleef ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
2022-12-13 13:58:16 +02:00
if ( owner . curInt - > cb - > battleCanFlee ( ) )
2022-11-18 17:54:10 +02:00
{
2022-12-21 17:06:47 +02:00
CFunctionList < void ( ) > ony = std : : bind ( & BattleWindow : : reallyFlee , this ) ;
2022-12-13 13:58:16 +02:00
owner . curInt - > showYesNoDialog ( CGI - > generaltexth - > allTexts [ 28 ] , ony , nullptr ) ; //Are you sure you want to retreat?
2022-11-18 17:54:10 +02:00
}
else
{
std : : vector < std : : shared_ptr < CComponent > > comps ;
std : : string heroName ;
//calculating fleeing hero's name
2022-12-13 13:58:16 +02:00
if ( owner . attackingHeroInstance )
if ( owner . attackingHeroInstance - > tempOwner = = owner . curInt - > cb - > getMyColor ( ) )
2023-01-02 13:27:03 +02:00
heroName = owner . attackingHeroInstance - > getNameTranslated ( ) ;
2022-12-13 13:58:16 +02:00
if ( owner . defendingHeroInstance )
if ( owner . defendingHeroInstance - > tempOwner = = owner . curInt - > cb - > getMyColor ( ) )
2023-01-02 13:27:03 +02:00
heroName = owner . defendingHeroInstance - > getNameTranslated ( ) ;
2022-11-18 17:54:10 +02:00
//calculating text
auto txt = boost : : format ( CGI - > generaltexth - > allTexts [ 340 ] ) % heroName ; //The Shackles of War are present. %s can not retreat!
//printing message
2022-12-13 13:58:16 +02:00
owner . curInt - > showInfoDialog ( boost : : to_string ( txt ) , comps ) ;
2022-11-18 17:54:10 +02:00
}
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : reallyFlee ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
owner . giveCommand ( EActionType : : RETREAT ) ;
2022-12-18 22:32:07 +02:00
CCS - > curh - > set ( Cursor : : Map : : POINTER ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : reallySurrender ( )
2022-11-18 17:54:10 +02:00
{
2023-04-05 02:26:29 +02:00
if ( owner . curInt - > cb - > getResourceAmount ( EGameResID : : GOLD ) < owner . curInt - > cb - > battleGetSurrenderCost ( ) )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
owner . curInt - > showInfoDialog ( CGI - > generaltexth - > allTexts [ 29 ] ) ; //You don't have enough gold!
2022-11-18 17:54:10 +02:00
}
else
{
2022-12-13 13:58:16 +02:00
owner . giveCommand ( EActionType : : SURRENDER ) ;
2022-12-18 22:32:07 +02:00
CCS - > curh - > set ( Cursor : : Map : : POINTER ) ;
2022-11-18 17:54:10 +02:00
}
}
2023-01-04 16:20:53 +02:00
void BattleWindow : : showAlternativeActionIcon ( PossiblePlayerBattleAction action )
2022-12-20 01:28:20 +02:00
{
2022-12-25 12:22:07 +02:00
auto w = widget < CButton > ( " alternativeAction " ) ;
if ( ! w )
return ;
std : : string iconName = variables [ " actionIconDefault " ] . String ( ) ;
2023-03-25 00:48:14 +02:00
switch ( action . get ( ) )
2022-12-20 01:28:20 +02:00
{
case PossiblePlayerBattleAction : : ATTACK :
2022-12-25 12:22:07 +02:00
iconName = variables [ " actionIconAttack " ] . String ( ) ;
2022-12-20 01:28:20 +02:00
break ;
case PossiblePlayerBattleAction : : SHOOT :
2022-12-25 12:22:07 +02:00
iconName = variables [ " actionIconShoot " ] . String ( ) ;
2022-12-20 01:28:20 +02:00
break ;
case PossiblePlayerBattleAction : : AIMED_SPELL_CREATURE :
2022-12-25 12:22:07 +02:00
iconName = variables [ " actionIconSpell " ] . String ( ) ;
2022-12-20 01:28:20 +02:00
break ;
2022-12-25 12:22:07 +02:00
//TODO: figure out purpose of this icon
//case PossiblePlayerBattleAction::???:
//iconName = variables["actionIconWalk"].String();
2022-12-20 01:28:20 +02:00
//break;
case PossiblePlayerBattleAction : : ATTACK_AND_RETURN :
2022-12-25 12:22:07 +02:00
iconName = variables [ " actionIconReturn " ] . String ( ) ;
2022-12-20 01:28:20 +02:00
break ;
case PossiblePlayerBattleAction : : WALK_AND_ATTACK :
2022-12-25 12:22:07 +02:00
iconName = variables [ " actionIconNoReturn " ] . String ( ) ;
2022-12-20 01:28:20 +02:00
break ;
}
auto anim = std : : make_shared < CAnimation > ( iconName ) ;
2023-05-03 18:05:07 +02:00
w - > setImage ( anim ) ;
2023-02-05 01:29:50 +02:00
w - > redraw ( ) ;
2022-12-20 01:28:20 +02:00
}
2023-01-04 16:20:53 +02:00
void BattleWindow : : setAlternativeActions ( const std : : list < PossiblePlayerBattleAction > & actions )
2022-12-20 01:28:20 +02:00
{
alternativeActions = actions ;
defaultAction = PossiblePlayerBattleAction : : INVALID ;
if ( alternativeActions . size ( ) > 1 )
defaultAction = alternativeActions . back ( ) ;
if ( ! alternativeActions . empty ( ) )
showAlternativeActionIcon ( alternativeActions . front ( ) ) ;
else
showAlternativeActionIcon ( defaultAction ) ;
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bAutofightf ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
//Stop auto-fight mode
2022-12-13 13:58:16 +02:00
if ( owner . curInt - > isAutoFightOn )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
assert ( owner . curInt - > autofightingAI ) ;
owner . curInt - > isAutoFightOn = false ;
2022-11-18 17:54:10 +02:00
logGlobal - > trace ( " Stopping the autofight... " ) ;
}
2022-12-13 13:58:16 +02:00
else if ( ! owner . curInt - > autofightingAI )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
owner . curInt - > isAutoFightOn = true ;
2022-11-18 17:54:10 +02:00
blockUI ( true ) ;
auto ai = CDynLibHandler : : getNewBattleAI ( settings [ " server " ] [ " friendlyAI " ] . String ( ) ) ;
2022-12-23 14:40:45 +02:00
ai - > initBattleInterface ( owner . curInt - > env , owner . curInt - > cb ) ;
2022-12-13 13:58:16 +02:00
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 ) ;
2022-11-18 17:54:10 +02:00
2022-12-13 13:58:16 +02:00
owner . requestAutofightingAIToTakeAction ( ) ;
2022-11-18 17:54:10 +02:00
}
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bSpellf ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
2023-01-21 16:15:20 +02:00
if ( ! owner . makingTurn ( ) )
2022-11-18 17:54:10 +02:00
return ;
2022-12-13 13:58:16 +02:00
auto myHero = owner . currentHero ( ) ;
2022-11-18 17:54:10 +02:00
if ( ! myHero )
return ;
2022-12-18 22:32:07 +02:00
CCS - > curh - > set ( Cursor : : Map : : POINTER ) ;
2022-11-18 17:54:10 +02:00
2022-12-13 13:58:16 +02:00
ESpellCastProblem : : ESpellCastProblem spellCastProblem = owner . curInt - > cb - > battleCanCastSpell ( myHero , spells : : Mode : : HERO ) ;
2022-11-18 17:54:10 +02:00
if ( spellCastProblem = = ESpellCastProblem : : OK )
{
2023-05-16 15:20:35 +02:00
GH . windows ( ) . createAndPushWindow < CSpellWindow > ( myHero , owner . curInt . get ( ) ) ;
2022-11-18 17:54:10 +02:00
}
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
2023-05-01 00:20:01 +02:00
auto blockingBonus = owner . currentHero ( ) - > getBonusLocalFirst ( Selector : : type ( ) ( BonusType : : BLOCK_ALL_MAGIC ) ) ;
2022-11-18 17:54:10 +02:00
if ( ! blockingBonus )
return ;
2023-05-01 00:20:01 +02:00
if ( blockingBonus - > source = = BonusSource : : ARTIFACT )
2022-11-18 17:54:10 +02:00
{
2022-12-01 23:58:01 +02:00
const auto artID = ArtifactID ( blockingBonus - > sid ) ;
2022-11-18 17:54:10 +02:00
//If we have artifact, put name of our hero. Otherwise assume it's the enemy.
//TODO check who *really* is source of bonus
2023-01-02 13:27:03 +02:00
std : : string heroName = myHero - > hasArt ( artID ) ? myHero - > getNameTranslated ( ) : owner . enemyHero ( ) . name ;
2022-11-18 17:54:10 +02:00
//%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 ] )
2023-01-02 15:58:56 +02:00
% heroName % CGI - > artifacts ( ) - > getByIndex ( artID ) - > getNameTranslated ( ) ) ) ;
2022-11-18 17:54:10 +02:00
}
}
}
2023-01-04 16:20:53 +02:00
void BattleWindow : : bSwitchActionf ( )
2022-12-20 01:28:20 +02:00
{
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 ( ) ;
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bWaitf ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
2022-12-13 13:58:16 +02:00
if ( owner . stacksController - > getActiveStack ( ) ! = nullptr )
owner . giveCommand ( EActionType : : WAIT ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bDefencef ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
2022-12-13 13:58:16 +02:00
if ( owner . stacksController - > getActiveStack ( ) ! = nullptr )
owner . giveCommand ( EActionType : : DEFEND ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bConsoleUpf ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
console - > scrollUp ( ) ;
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bConsoleDownf ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
if ( owner . actionsController - > spellcastingModeActive ( ) )
2022-11-18 17:54:10 +02:00
return ;
console - > scrollDown ( ) ;
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bTacticNextStack ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
owner . tacticNextStack ( nullptr ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : bTacticPhaseEnd ( )
2022-11-18 17:54:10 +02:00
{
2022-12-13 13:58:16 +02:00
owner . tacticPhaseEnd ( ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:06:47 +02:00
void BattleWindow : : blockUI ( bool on )
2022-11-18 17:54:10 +02:00
{
bool canCastSpells = false ;
2022-12-13 13:58:16 +02:00
auto hero = owner . curInt - > cb - > battleGetMyHero ( ) ;
2022-11-18 17:54:10 +02:00
if ( hero )
{
2022-12-13 13:58:16 +02:00
ESpellCastProblem : : ESpellCastProblem spellcastingProblem = owner . curInt - > cb - > battleCanCastSpell ( hero , spells : : Mode : : HERO ) ;
2022-11-18 17:54:10 +02:00
//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 ;
}
2022-12-13 13:58:16 +02:00
bool canWait = owner . stacksController - > getActiveStack ( ) ? ! owner . stacksController - > getActiveStack ( ) - > waitedThisTurn : false ;
2022-11-18 17:54:10 +02:00
2023-04-29 12:48:21 +02:00
setShortcutBlocked ( EShortcut : : GLOBAL_OPTIONS , on ) ;
setShortcutBlocked ( EShortcut : : BATTLE_RETREAT , on | | ! owner . curInt - > cb - > battleCanFlee ( ) ) ;
setShortcutBlocked ( EShortcut : : BATTLE_SURRENDER , on | | owner . curInt - > cb - > battleGetSurrenderCost ( ) < 0 ) ;
setShortcutBlocked ( EShortcut : : BATTLE_CAST_SPELL , on | | owner . tacticsMode | | ! canCastSpells ) ;
setShortcutBlocked ( EShortcut : : BATTLE_WAIT , on | | owner . tacticsMode | | ! canWait ) ;
setShortcutBlocked ( EShortcut : : BATTLE_DEFEND , on | | owner . tacticsMode ) ;
setShortcutBlocked ( EShortcut : : BATTLE_SELECT_ACTION , on | | owner . tacticsMode ) ;
setShortcutBlocked ( EShortcut : : BATTLE_AUTOCOMBAT , owner . actionsController - > spellcastingModeActive ( ) ) ;
setShortcutBlocked ( EShortcut : : BATTLE_TACTICS_END , on & & owner . tacticsMode ) ;
setShortcutBlocked ( EShortcut : : BATTLE_TACTICS_NEXT , on & & owner . tacticsMode ) ;
setShortcutBlocked ( EShortcut : : BATTLE_CONSOLE_DOWN , on & & ! owner . tacticsMode ) ;
setShortcutBlocked ( EShortcut : : BATTLE_CONSOLE_UP , on & & ! owner . tacticsMode ) ;
2022-11-18 17:54:10 +02:00
}
2022-12-21 17:02:53 +02:00
2023-04-16 19:42:56 +02:00
std : : optional < uint32_t > BattleWindow : : getQueueHoveredUnitId ( )
2023-01-22 21:03:11 +02:00
{
return queue - > getHoveredUnitIdIfAny ( ) ;
}
2023-06-02 15:42:18 +02:00
void BattleWindow : : showAll ( Canvas & to )
2022-12-21 17:02:53 +02:00
{
CIntObject : : showAll ( to ) ;
2023-02-03 18:23:53 +02:00
if ( GH . screenDimensions ( ) . x ! = 800 | | GH . screenDimensions ( ) . y ! = 600 )
2023-06-02 15:42:18 +02:00
CMessage : : drawBorder ( owner . curInt - > playerID , to . getInternalSurface ( ) , pos . w + 28 , pos . h + 29 , pos . x - 14 , pos . y - 15 ) ;
2022-12-21 17:02:53 +02:00
}
2023-06-02 15:42:18 +02:00
void BattleWindow : : show ( Canvas & to )
2022-12-21 17:02:53 +02:00
{
CIntObject : : show ( to ) ;
LOCPLINT - > cingconsole - > show ( to ) ;
}
2023-01-04 16:20:53 +02:00
void BattleWindow : : close ( )
{
2023-05-16 17:34:23 +02:00
if ( ! GH . windows ( ) . isTopWindow ( this ) )
2023-01-04 16:20:53 +02:00
logGlobal - > error ( " Only top interface must be closed " ) ;
2023-05-16 15:20:35 +02:00
GH . windows ( ) . popWindows ( 1 ) ;
2023-01-04 16:20:53 +02:00
}