2017-07-13 10:26:03 +02:00
/*
* CBattleInterface . 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
*
*/
2011-12-14 00:35:28 +03:00
# include "StdInc.h"
2022-12-09 13:38:46 +02:00
# include "BattleInterface.h"
2011-12-14 00:35:28 +03:00
2022-12-09 13:38:46 +02:00
# include "BattleAnimationClasses.h"
# include "BattleActionsController.h"
# include "BattleInterfaceClasses.h"
# include "CreatureAnimation.h"
# include "BattleProjectileController.h"
# include "BattleEffectsController.h"
# include "BattleObstacleController.h"
# include "BattleSiegeController.h"
# include "BattleFieldController.h"
# include "BattleControlPanel.h"
# include "BattleStacksController.h"
# include "BattleRenderer.h"
2014-07-13 20:53:37 +03:00
# include "../CGameInfo.h"
2011-12-14 00:35:28 +03:00
# include "../CMessage.h"
2014-07-13 20:53:37 +03:00
# include "../CMusicHandler.h"
# include "../CPlayerInterface.h"
2022-11-25 16:32:23 +02:00
# include "../gui/CCanvas.h"
2014-07-13 20:53:37 +03:00
# include "../gui/CCursorHandler.h"
# include "../gui/CGuiHandler.h"
# include "../windows/CAdvmapInterface.h"
2011-12-14 00:35:28 +03:00
# include "../../CCallback.h"
2017-03-17 17:48:44 +02:00
# include "../../lib/CStack.h"
2012-09-29 13:59:43 +03:00
# include "../../lib/CConfigHandler.h"
2014-07-13 20:53:37 +03:00
# include "../../lib/CGeneralTextHandler.h"
# include "../../lib/CHeroHandler.h"
2011-12-14 00:35:28 +03:00
# include "../../lib/CondSh.h"
2022-11-27 02:26:02 +02:00
# include "../../lib/mapObjects/CGTownInstance.h"
2014-07-13 20:53:37 +03:00
# include "../../lib/NetPacks.h"
2012-02-20 00:03:43 +03:00
# include "../../lib/UnlockGuard.h"
2009-01-15 19:01:08 +02:00
2022-12-09 13:26:17 +02:00
CondSh < bool > BattleInterface : : animsAreDisplayed ( false ) ;
CondSh < BattleAction * > BattleInterface : : givenCommand ( nullptr ) ;
2009-03-28 20:46:20 +02:00
2022-12-09 13:26:17 +02:00
BattleInterface : : BattleInterface ( const CCreatureSet * army1 , const CCreatureSet * army2 ,
2018-07-25 00:36:48 +02:00
const CGHeroInstance * hero1 , const CGHeroInstance * hero2 ,
const SDL_Rect & myRect ,
std : : shared_ptr < CPlayerInterface > att , std : : shared_ptr < CPlayerInterface > defen , std : : shared_ptr < CPlayerInterface > spectatorInt )
2022-11-17 23:57:51 +02:00
: attackingHeroInstance ( hero1 ) , defendingHeroInstance ( hero2 ) , animCount ( 0 ) ,
2022-11-20 19:11:34 +02:00
attackerInt ( att ) , defenderInt ( defen ) , curInt ( att ) ,
2019-03-22 22:39:53 +02:00
myTurn ( false ) , moveStarted ( false ) , moveSoundHander ( - 1 ) , bresult ( nullptr ) , battleActionsStarted ( false )
2009-09-10 14:28:34 +03:00
{
2011-12-17 21:59:59 +03:00
OBJ_CONSTRUCTION ;
2009-09-10 14:28:34 +03:00
2022-12-09 13:26:17 +02:00
projectilesController . reset ( new BattleProjectileController ( this ) ) ;
2022-11-17 13:21:03 +02:00
2017-06-03 07:25:10 +02:00
if ( spectatorInt )
2018-07-25 00:36:48 +02:00
{
2017-06-03 07:25:10 +02:00
curInt = spectatorInt ;
2018-07-25 00:36:48 +02:00
}
2017-06-03 07:25:10 +02:00
else if ( ! curInt )
2013-06-23 00:47:51 +03:00
{
//May happen when we are defending during network MP game -> attacker interface is just not present
2014-03-07 16:21:09 +03:00
curInt = defenderInt ;
2013-06-23 00:47:51 +03:00
}
2010-01-28 19:23:01 +02:00
2011-12-14 00:35:28 +03:00
animsAreDisplayed . setn ( false ) ;
pos = myRect ;
strongInterest = true ;
2017-06-14 03:53:26 +02:00
givenCommand . setn ( nullptr ) ;
2010-01-28 19:23:01 +02:00
2013-11-09 19:25:20 +03:00
//hot-seat -> check tactics for both players (defender may be local human)
2018-07-25 00:36:48 +02:00
if ( attackerInt & & attackerInt - > cb - > battleGetTacticDist ( ) )
2011-12-14 00:35:28 +03:00
tacticianInterface = attackerInt ;
2018-07-25 00:36:48 +02:00
else if ( defenderInt & & defenderInt - > cb - > battleGetTacticDist ( ) )
2011-12-14 00:35:28 +03:00
tacticianInterface = defenderInt ;
2010-01-28 19:23:01 +02:00
2013-11-09 19:25:20 +03:00
//if we found interface of player with tactics, then enter tactics mode
tacticsMode = static_cast < bool > ( tacticianInterface ) ;
2010-01-28 19:23:01 +02:00
2011-12-14 00:35:28 +03:00
//create stack queue
2017-07-20 06:08:49 +02:00
bool embedQueue ;
std : : string queueSize = settings [ " battle " ] [ " queueSize " ] . String ( ) ;
if ( queueSize = = " auto " )
embedQueue = screen - > h < 700 ;
else
embedQueue = screen - > h < 700 | | queueSize = = " small " ;
2022-12-09 13:26:17 +02:00
queue = std : : make_shared < StackQueue > ( embedQueue , this ) ;
2017-07-20 06:08:49 +02:00
if ( ! embedQueue )
2011-12-14 00:35:28 +03:00
{
2016-10-28 23:37:20 +02:00
if ( settings [ " battle " ] [ " showQueue " ] . Bool ( ) )
2011-12-14 00:35:28 +03:00
pos . y + = queue - > pos . h / 2 ; //center whole window
2010-01-28 19:23:01 +02:00
2011-12-22 16:05:19 +03:00
queue - > moveTo ( Point ( pos . x , pos . y - queue - > pos . h ) ) ;
2011-12-14 00:35:28 +03:00
}
2010-01-28 19:23:01 +02:00
2011-12-14 00:35:28 +03:00
//preparing siege info
2016-10-28 23:37:20 +02:00
const CGTownInstance * town = curInt - > cb - > battleGetDefendedTown ( ) ;
2018-07-25 00:36:48 +02:00
if ( town & & town - > hasFort ( ) )
2022-12-09 13:26:17 +02:00
siegeController . reset ( new BattleSiegeController ( this , town ) ) ;
2010-01-28 19:23:01 +02:00
2018-07-25 00:36:48 +02:00
CPlayerInterface : : battleInt = this ;
2010-01-28 19:23:01 +02:00
2011-12-14 00:35:28 +03:00
//initializing armies
this - > army1 = army1 ;
this - > army2 = army2 ;
2009-09-17 15:59:04 +03:00
2022-12-09 13:26:17 +02:00
controlPanel = std : : make_shared < BattleControlPanel > ( this , Point ( 0 , 556 ) ) ;
2022-11-27 02:26:02 +02:00
2011-12-14 00:35:28 +03:00
//preparing menu background and terrain
2022-12-09 13:26:17 +02:00
fieldController . reset ( new BattleFieldController ( this ) ) ;
stacksController . reset ( new BattleStacksController ( this ) ) ;
actionsController . reset ( new BattleActionsController ( this ) ) ;
effectsController . reset ( new BattleEffectsController ( this ) ) ;
2022-11-27 02:26:02 +02:00
2011-12-14 00:35:28 +03:00
//loading hero animations
2018-07-25 00:36:48 +02:00
if ( hero1 ) // attacking hero
2009-09-16 13:09:08 +03:00
{
2012-12-16 16:47:53 +03:00
std : : string battleImage ;
2018-08-27 08:42:36 +02:00
if ( ! hero1 - > type - > battleImage . empty ( ) )
{
battleImage = hero1 - > type - > battleImage ;
}
2012-12-16 16:47:53 +03:00
else
2018-08-27 08:42:36 +02:00
{
if ( hero1 - > sex )
battleImage = hero1 - > type - > heroClass - > imageBattleFemale ;
else
battleImage = hero1 - > type - > heroClass - > imageBattleMale ;
}
2012-12-16 16:47:53 +03:00
2022-12-09 13:26:17 +02:00
attackingHero = std : : make_shared < BattleHero > ( battleImage , false , hero1 - > tempOwner , hero1 - > tempOwner = = curInt - > playerID ? hero1 : nullptr , this ) ;
2017-09-05 15:44:27 +02:00
2018-03-30 13:02:04 +02:00
auto img = attackingHero - > animation - > getImage ( 0 , 0 , true ) ;
2017-09-05 15:44:27 +02:00
if ( img )
attackingHero - > pos = genRect ( img - > height ( ) , img - > width ( ) , pos . x - 43 , pos . y - 19 ) ;
2009-09-16 13:09:08 +03:00
}
2018-07-25 00:36:48 +02:00
if ( hero2 ) // defending hero
2009-09-16 13:09:08 +03:00
{
2012-12-16 16:47:53 +03:00
std : : string battleImage ;
2018-08-27 08:42:36 +02:00
if ( ! hero2 - > type - > battleImage . empty ( ) )
{
battleImage = hero2 - > type - > battleImage ;
}
2012-12-16 16:47:53 +03:00
else
2018-08-27 08:42:36 +02:00
{
if ( hero2 - > sex )
battleImage = hero2 - > type - > heroClass - > imageBattleFemale ;
else
battleImage = hero2 - > type - > heroClass - > imageBattleMale ;
}
2012-12-16 16:47:53 +03:00
2022-12-09 13:26:17 +02:00
defendingHero = std : : make_shared < BattleHero > ( battleImage , true , hero2 - > tempOwner , hero2 - > tempOwner = = curInt - > playerID ? hero2 : nullptr , this ) ;
2017-09-05 15:44:27 +02:00
2018-03-30 13:02:04 +02:00
auto img = defendingHero - > animation - > getImage ( 0 , 0 , true ) ;
2017-09-05 15:44:27 +02:00
if ( img )
defendingHero - > pos = genRect ( img - > height ( ) , img - > width ( ) , pos . x + 693 , pos . y - 19 ) ;
2009-09-16 13:09:08 +03:00
}
2018-07-25 00:36:48 +02:00
2022-12-09 13:26:17 +02:00
obstacleController . reset ( new BattleObstacleController ( this ) ) ;
2009-09-10 14:28:34 +03:00
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
if ( tacticsMode )
2022-11-18 17:54:10 +02:00
tacticNextStack ( nullptr ) ;
2009-09-10 14:28:34 +03:00
2011-12-14 00:35:28 +03:00
CCS - > musich - > stopMusic ( ) ;
2019-03-22 22:39:53 +02:00
battleIntroSoundChannel = CCS - > soundh - > playSoundFromSet ( CCS - > soundh - > battleIntroSounds ) ;
auto onIntroPlayed = [ & ] ( )
2012-08-06 10:34:37 +03:00
{
2019-03-22 22:39:53 +02:00
if ( LOCPLINT - > battleInt )
{
2022-11-13 14:24:15 +02:00
CCS - > musich - > playMusicFromSet ( " battle " , true , true ) ;
2019-03-22 22:39:53 +02:00
battleActionsStarted = true ;
2022-11-27 15:10:27 +02:00
activateStack ( ) ;
2022-12-01 22:06:42 +02:00
controlPanel - > blockUI ( settings [ " session " ] [ " spectate " ] . Bool ( ) | | stacksController - > getActiveStack ( ) = = nullptr ) ;
2019-03-22 22:39:53 +02:00
battleIntroSoundChannel = - 1 ;
}
2012-08-06 10:34:37 +03:00
} ;
2019-03-22 22:39:53 +02:00
CCS - > soundh - > setCallback ( battleIntroSoundChannel , onIntroPlayed ) ;
2012-04-04 11:03:52 +03:00
2012-06-02 18:16:54 +03:00
addUsedEvents ( RCLICK | MOVE | KEYBOARD ) ;
2022-11-18 17:54:10 +02:00
controlPanel - > blockUI ( true ) ;
2022-11-29 14:59:50 +02:00
queue - > update ( ) ;
2009-09-10 14:28:34 +03:00
}
2022-12-09 13:26:17 +02:00
BattleInterface : : ~ BattleInterface ( )
2009-09-10 14:28:34 +03:00
{
2018-07-25 00:36:48 +02:00
CPlayerInterface : : battleInt = nullptr ;
2022-11-20 19:11:34 +02:00
givenCommand . cond . notify_all ( ) ; //that two lines should make any stacksController->getActiveStack() waiting thread to finish
2012-02-20 00:03:43 +03:00
2011-12-14 00:35:28 +03:00
if ( active ) //dirty fix for #485
2009-09-10 14:28:34 +03:00
{
2011-12-14 00:35:28 +03:00
deactivate ( ) ;
2009-09-10 14:28:34 +03:00
}
2016-10-28 23:37:20 +02:00
if ( adventureInt & & adventureInt - > selection )
2011-12-14 00:35:28 +03:00
{
2022-12-01 22:06:42 +02:00
//FIXME: this should be moved to adventureInt which should restore correct track based on selection/active player
2022-09-25 21:47:44 +02:00
const auto & terrain = * ( LOCPLINT - > cb - > getTile ( adventureInt - > selection - > visitablePos ( ) ) - > terType ) ;
2022-11-13 14:24:15 +02:00
CCS - > musich - > playMusicFromSet ( " terrain " , terrain . name , true , false ) ;
2011-12-14 00:35:28 +03:00
}
2017-06-05 17:43:02 +02:00
animsAreDisplayed . setn ( false ) ;
2009-09-10 14:28:34 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : setPrintCellBorders ( bool set )
2009-09-10 14:28:34 +03:00
{
2012-01-12 18:23:00 +03:00
Settings cellBorders = settings . write [ " battle " ] [ " cellBorders " ] ;
cellBorders - > Bool ( ) = set ;
2022-11-20 19:11:34 +02:00
fieldController - > redrawBackgroundWithHexes ( ) ;
2011-12-14 00:35:28 +03:00
GH . totalRedraw ( ) ;
2009-09-10 14:28:34 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : setPrintStackRange ( bool set )
2011-12-14 00:35:28 +03:00
{
2012-01-12 18:23:00 +03:00
Settings stackRange = settings . write [ " battle " ] [ " stackRange " ] ;
stackRange - > Bool ( ) = set ;
2022-11-20 19:11:34 +02:00
fieldController - > redrawBackgroundWithHexes ( ) ;
2011-12-14 00:35:28 +03:00
GH . totalRedraw ( ) ;
}
2009-09-10 14:28:34 +03:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : setPrintMouseShadow ( bool set )
2009-09-10 14:28:34 +03:00
{
2012-01-12 18:23:00 +03:00
Settings shadow = settings . write [ " battle " ] [ " mouseShadow " ] ;
shadow - > Bool ( ) = set ;
2011-12-14 00:35:28 +03:00
}
2009-09-10 14:28:34 +03:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : activate ( )
2011-12-14 00:35:28 +03:00
{
2022-11-18 17:54:10 +02:00
controlPanel - > activate ( ) ;
2016-10-28 23:37:20 +02:00
if ( curInt - > isAutoFightOn )
2013-06-23 00:47:51 +03:00
return ;
2012-06-02 18:16:54 +03:00
CIntObject : : activate ( ) ;
2012-06-09 19:45:45 +03:00
2016-10-28 23:37:20 +02:00
if ( attackingHero )
2011-12-14 00:35:28 +03:00
attackingHero - > activate ( ) ;
2016-10-28 23:37:20 +02:00
if ( defendingHero )
2011-12-14 00:35:28 +03:00
defendingHero - > activate ( ) ;
2022-09-11 10:31:24 +02:00
2022-11-17 23:57:51 +02:00
fieldController - > activate ( ) ;
2022-09-11 10:31:24 +02:00
2016-10-28 23:37:20 +02:00
if ( settings [ " battle " ] [ " showQueue " ] . Bool ( ) )
2011-12-14 00:35:28 +03:00
queue - > activate ( ) ;
2009-09-10 14:28:34 +03:00
2011-12-14 00:35:28 +03:00
LOCPLINT - > cingconsole - > activate ( ) ;
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : deactivate ( )
2011-12-14 00:35:28 +03:00
{
2022-11-18 17:54:10 +02:00
controlPanel - > deactivate ( ) ;
2012-06-02 18:16:54 +03:00
CIntObject : : deactivate ( ) ;
2022-11-17 23:57:51 +02:00
fieldController - > deactivate ( ) ;
2012-06-09 19:45:45 +03:00
2016-10-28 23:37:20 +02:00
if ( attackingHero )
2011-12-14 00:35:28 +03:00
attackingHero - > deactivate ( ) ;
2016-10-28 23:37:20 +02:00
if ( defendingHero )
2011-12-14 00:35:28 +03:00
defendingHero - > deactivate ( ) ;
2016-10-28 23:37:20 +02:00
if ( settings [ " battle " ] [ " showQueue " ] . Bool ( ) )
2011-12-14 00:35:28 +03:00
queue - > deactivate ( ) ;
2009-09-11 15:46:26 +03:00
2011-12-14 00:35:28 +03:00
LOCPLINT - > cingconsole - > deactivate ( ) ;
2009-09-10 14:28:34 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : keyPressed ( const SDL_KeyboardEvent & key )
2011-12-14 00:35:28 +03:00
{
2021-02-20 03:57:50 +02:00
if ( key . keysym . sym = = SDLK_q & & key . state = = SDL_PRESSED )
2009-09-04 17:11:42 +03:00
{
2021-02-20 03:57:50 +02:00
if ( settings [ " battle " ] [ " showQueue " ] . Bool ( ) ) //hide queue
2011-12-14 00:35:28 +03:00
hideQueue ( ) ;
else
showQueue ( ) ;
2009-09-21 11:29:41 +03:00
2011-12-14 00:35:28 +03:00
}
2021-02-20 03:57:50 +02:00
else if ( key . keysym . sym = = SDLK_f & & key . state = = SDL_PRESSED )
2016-10-15 22:50:12 +02:00
{
2022-11-20 22:56:42 +02:00
actionsController - > enterCreatureCastingMode ( ) ;
2016-10-15 22:50:12 +02:00
}
2021-02-20 03:57:50 +02:00
else if ( key . keysym . sym = = SDLK_ESCAPE )
2009-01-15 19:01:08 +02:00
{
2019-03-22 22:39:53 +02:00
if ( ! battleActionsStarted )
CCS - > soundh - > stopSound ( battleIntroSoundChannel ) ;
else
2022-11-20 22:56:42 +02:00
actionsController - > endCastingSpell ( ) ;
2009-01-15 19:01:08 +02:00
}
2011-12-14 00:35:28 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : mouseMoved ( const SDL_MouseMotionEvent & event )
2011-12-14 00:35:28 +03:00
{
2022-11-17 23:57:51 +02:00
BattleHex selectedHex = fieldController - > getHoveredHex ( ) ;
2011-12-14 00:35:28 +03:00
2022-11-20 22:56:42 +02:00
actionsController - > handleHex ( selectedHex , MOVE ) ;
2022-12-01 23:39:43 +02:00
controlPanel - > mouseMoved ( event ) ;
2009-01-15 19:01:08 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : clickRight ( tribool down , bool previousState )
2009-09-24 16:44:55 +03:00
{
2016-10-28 23:37:20 +02:00
if ( ! down )
2009-09-24 16:44:55 +03:00
{
2022-11-20 22:56:42 +02:00
actionsController - > endCastingSpell ( ) ;
2011-12-14 00:35:28 +03:00
}
}
2009-09-24 16:44:55 +03:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : stackReset ( const CStack * stack )
2011-12-14 00:35:28 +03:00
{
2022-11-20 19:11:34 +02:00
stacksController - > stackReset ( stack ) ;
}
2014-03-07 16:21:09 +03:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : stackAdded ( const CStack * stack )
2022-11-20 19:11:34 +02:00
{
stacksController - > stackAdded ( stack ) ;
2011-12-14 00:35:28 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : stackRemoved ( uint32_t stackID )
2011-12-14 00:35:28 +03:00
{
2022-11-20 19:11:34 +02:00
stacksController - > stackRemoved ( stackID ) ;
fieldController - > redrawBackgroundWithHexes ( ) ;
2012-02-22 20:43:59 +03:00
queue - > update ( ) ;
2011-12-14 00:35:28 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : stackActivated ( const CStack * stack ) //TODO: check it all before game state is changed due to abilities
2011-12-14 00:35:28 +03:00
{
2022-11-20 19:11:34 +02:00
stacksController - > stackActivated ( stack ) ;
2011-12-14 00:35:28 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : stackMoved ( const CStack * stack , std : : vector < BattleHex > destHex , int distance )
2011-12-14 00:35:28 +03:00
{
2022-11-20 19:11:34 +02:00
stacksController - > stackMoved ( stack , destHex , distance ) ;
2011-12-14 00:35:28 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : stacksAreAttacked ( std : : vector < StackAttackedInfo > attackedInfos )
2011-12-14 00:35:28 +03:00
{
2022-11-20 19:11:34 +02:00
stacksController - > stacksAreAttacked ( attackedInfos ) ;
2017-09-27 16:35:30 +02:00
std : : array < int , 2 > killedBySide = { 0 , 0 } ;
2022-09-22 10:49:55 +02:00
int targets = 0 ;
2017-09-27 16:35:30 +02:00
for ( const StackAttackedInfo & attackedInfo : attackedInfos )
2009-11-08 16:44:58 +02:00
{
2011-12-14 00:35:28 +03:00
+ + targets ;
2017-09-27 16:35:30 +02:00
ui8 side = attackedInfo . defender - > side ;
killedBySide . at ( side ) + = attackedInfo . amountKilled ;
}
for ( ui8 side = 0 ; side < 2 ; side + + )
{
if ( killedBySide . at ( side ) > killedBySide . at ( 1 - side ) )
2022-12-01 22:06:42 +02:00
setHeroAnimation ( side , CCreatureAnim : : HERO_DEFEAT ) ;
2017-09-27 16:35:30 +02:00
else if ( killedBySide . at ( side ) < killedBySide . at ( 1 - side ) )
2022-12-01 22:06:42 +02:00
setHeroAnimation ( side , CCreatureAnim : : HERO_VICTORY ) ;
2009-11-08 16:44:58 +02:00
}
2009-03-21 18:03:07 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : stackAttacking ( const CStack * attacker , BattleHex dest , const CStack * attacked , bool shooting )
2009-03-21 18:03:07 +02:00
{
2022-11-20 19:11:34 +02:00
stacksController - > stackAttacking ( attacker , dest , attacked , shooting ) ;
2011-12-14 00:35:28 +03:00
}
2011-01-18 19:23:31 +02:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : newRoundFirst ( int round )
2011-12-14 00:35:28 +03:00
{
waitForAnims ( ) ;
}
2011-01-18 19:23:31 +02:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : newRound ( int number )
2011-12-14 00:35:28 +03:00
{
2022-11-18 17:54:10 +02:00
controlPanel - > console - > addText ( CGI - > generaltexth - > allTexts [ 412 ] ) ;
2011-12-14 00:35:28 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : giveCommand ( EActionType action , BattleHex tile , si32 additional )
2011-12-14 00:35:28 +03:00
{
2017-07-20 06:08:49 +02:00
const CStack * actor = nullptr ;
if ( action ! = EActionType : : HERO_SPELL & & action ! = EActionType : : RETREAT & & action ! = EActionType : : SURRENDER )
2011-12-14 00:35:28 +03:00
{
2022-11-20 19:11:34 +02:00
actor = stacksController - > getActiveStack ( ) ;
2009-01-15 19:01:08 +02:00
}
2012-04-03 02:23:14 +03:00
2017-07-20 06:08:49 +02:00
auto side = curInt - > cb - > playerToSide ( curInt - > playerID ) ;
if ( ! side )
{
logGlobal - > error ( " Player %s is not in battle " , curInt - > playerID . getStr ( ) ) ;
return ;
}
2012-04-03 02:23:14 +03:00
2022-11-20 19:11:34 +02:00
auto ba = new BattleAction ( ) ; //is deleted in CPlayerInterface::stacksController->getActiveStack()()
2017-07-20 06:08:49 +02:00
ba - > side = side . get ( ) ;
2011-12-14 00:35:28 +03:00
ba - > actionType = action ;
2017-07-20 06:08:49 +02:00
ba - > aimToHex ( tile ) ;
ba - > actionSubtype = additional ;
sendCommand ( ba , actor ) ;
}
2011-01-18 19:23:31 +02:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : sendCommand ( BattleAction * & command , const CStack * actor )
2017-07-20 06:08:49 +02:00
{
command - > stackNumber = actor ? actor - > unitId ( ) : ( ( command - > side = = BattleSide : : ATTACKER ) ? - 1 : - 2 ) ;
if ( ! tacticsMode )
2010-03-02 13:40:29 +02:00
{
2017-07-20 06:08:49 +02:00
logGlobal - > trace ( " Setting command for %s " , ( actor ? actor - > nodeName ( ) : " hero " ) ) ;
2011-12-14 00:35:28 +03:00
myTurn = false ;
2022-11-20 19:11:34 +02:00
stacksController - > setActiveStack ( nullptr ) ;
2017-07-20 06:08:49 +02:00
givenCommand . setn ( command ) ;
2011-12-14 00:35:28 +03:00
}
else
{
2017-07-20 06:08:49 +02:00
curInt - > cb - > battleMakeTacticAction ( command ) ;
vstd : : clear_pointer ( command ) ;
2022-11-20 19:11:34 +02:00
stacksController - > setActiveStack ( nullptr ) ;
2012-04-03 02:23:14 +03:00
//next stack will be activated when action ends
2010-03-02 13:40:29 +02:00
}
2009-01-15 19:01:08 +02:00
}
2022-12-09 13:26:17 +02:00
const CGHeroInstance * BattleInterface : : getActiveHero ( )
2011-12-14 00:35:28 +03:00
{
2022-11-20 19:11:34 +02:00
const CStack * attacker = stacksController - > getActiveStack ( ) ;
2017-07-01 10:34:00 +02:00
if ( ! attacker )
2009-01-15 19:01:08 +02:00
{
2013-06-26 14:18:27 +03:00
return nullptr ;
2011-12-14 00:35:28 +03:00
}
2017-07-01 10:34:00 +02:00
if ( attacker - > side = = BattleSide : : ATTACKER )
2011-12-14 00:35:28 +03:00
{
return attackingHeroInstance ;
}
2012-02-16 20:10:58 +03:00
2011-12-14 00:35:28 +03:00
return defendingHeroInstance ;
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : hexLclicked ( int whichOne )
2011-12-14 00:35:28 +03:00
{
2022-11-20 22:56:42 +02:00
actionsController - > handleHex ( whichOne , LCLICK ) ;
2009-01-15 19:01:08 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : stackIsCatapulting ( const CatapultAttack & ca )
2009-09-15 15:20:11 +03:00
{
2022-11-17 18:50:12 +02:00
if ( siegeController )
siegeController - > stackIsCatapulting ( ca ) ;
}
2016-02-10 06:10:32 +02:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : gateStateChanged ( const EGateState state )
2022-11-17 18:50:12 +02:00
{
if ( siegeController )
siegeController - > gateStateChanged ( state ) ;
2009-09-15 15:20:11 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : battleFinished ( const BattleResult & br )
2009-01-15 19:01:08 +02:00
{
2011-12-14 00:35:28 +03:00
bresult = & br ;
2012-02-20 00:03:43 +03:00
{
2016-11-25 21:12:22 +02:00
auto unlockPim = vstd : : makeUnlockGuard ( * CPlayerInterface : : pim ) ;
2012-02-20 00:03:43 +03:00
animsAreDisplayed . waitUntil ( false ) ;
}
2022-11-20 19:11:34 +02:00
stacksController - > setActiveStack ( nullptr ) ;
2017-05-13 09:54:03 +02:00
displayBattleFinished ( ) ;
2009-01-15 19:01:08 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : displayBattleFinished ( )
2009-04-16 17:01:27 +03:00
{
2012-12-14 18:32:53 +03:00
CCS - > curh - > changeGraphic ( ECursor : : ADVENTURE , 0 ) ;
2017-06-03 07:25:10 +02:00
if ( settings [ " session " ] [ " spectate " ] . Bool ( ) & & settings [ " session " ] [ " spectate-skip-battle-result " ] . Bool ( ) )
{
2018-07-25 00:36:48 +02:00
close ( ) ;
2017-06-03 07:25:10 +02:00
return ;
}
2012-02-16 20:10:58 +03:00
2022-12-09 13:26:17 +02:00
GH . pushInt ( std : : make_shared < BattleResultWindow > ( * bresult , * ( this - > curInt ) ) ) ;
2017-03-19 04:15:31 +02:00
curInt - > waitWhileDialog ( ) ; // Avoid freeze when AI end turn after battle. Check bug #1897
2018-07-25 00:36:48 +02:00
CPlayerInterface : : battleInt = nullptr ;
2009-04-16 17:01:27 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : spellCast ( const BattleSpellCast * sc )
2009-08-26 17:09:55 +03:00
{
2017-07-20 06:08:49 +02:00
const SpellID spellID = sc - > spellID ;
const CSpell * spell = spellID . toSpell ( ) ;
2022-12-01 22:06:42 +02:00
assert ( spell ) ;
2017-07-20 06:08:49 +02:00
if ( ! spell )
return ;
2009-08-26 17:09:55 +03:00
2017-07-20 06:08:49 +02:00
const std : : string & castSoundPath = spell - > getCastSound ( ) ;
2015-02-07 10:13:24 +02:00
2016-10-28 23:37:20 +02:00
if ( ! castSoundPath . empty ( ) )
2014-03-10 19:00:58 +03:00
CCS - > soundh - > playSound ( castSoundPath ) ;
2014-11-27 20:06:11 +02:00
2022-12-01 22:06:42 +02:00
if ( sc - > activeCast )
2014-11-27 20:06:11 +02:00
{
2022-12-01 22:06:42 +02:00
const CStack * casterStack = curInt - > cb - > battleGetStackByID ( sc - > casterStack ) ;
2014-11-27 20:33:57 +02:00
2022-12-01 22:06:42 +02:00
if ( casterStack ! = nullptr )
2014-11-27 20:06:11 +02:00
{
2022-12-01 22:06:42 +02:00
displaySpellCast ( spellID , casterStack - > getPosition ( ) ) ;
2015-02-07 10:13:24 +02:00
2022-12-01 22:06:42 +02:00
stacksController - > addNewAnim ( new CCastAnimation ( this , casterStack , sc - > tile , curInt - > cb - > battleGetStackByPos ( sc - > tile ) , spell ) ) ;
}
else
if ( sc - > tile . isValid ( ) & & ! spell - > animationInfo . projectile . empty ( ) )
2009-08-26 17:09:55 +03:00
{
2022-12-01 22:06:42 +02:00
// this is spell cast by hero with valid destination & valid projectile -> play animation
2017-09-05 19:45:29 +02:00
2022-12-01 22:06:42 +02:00
const CStack * target = curInt - > cb - > battleGetStackByPos ( sc - > tile ) ;
Point srccoord = ( sc - > side ? Point ( 770 , 60 ) : Point ( 30 , 60 ) ) + pos ; //hero position
Point destcoord = stacksController - > getStackPositionAtHex ( sc - > tile , target ) ; //position attacked by projectile
destcoord + = Point ( 250 , 240 ) ; // FIXME: what are these constants?
2012-02-16 20:10:58 +03:00
2022-12-01 22:06:42 +02:00
projectilesController - > createSpellProjectile ( nullptr , target , srccoord , destcoord , spell ) ;
projectilesController - > emitStackProjectile ( nullptr ) ;
2011-12-14 00:35:28 +03:00
2022-12-01 22:06:42 +02:00
// wait fo projectile to end
stacksController - > addNewAnim ( new CWaitingProjectileAnimation ( this , nullptr ) ) ;
2014-11-26 23:27:38 +02:00
}
2015-03-22 11:18:58 +02:00
}
2017-09-08 13:25:12 +02:00
waitForAnims ( ) ; //wait for projectile animation
2015-03-22 11:18:58 +02:00
2014-11-27 23:36:14 +02:00
displaySpellHit ( spellID , sc - > tile ) ;
2015-03-22 11:18:58 +02:00
2015-09-14 04:45:05 +02:00
//queuing affect animation
2017-07-20 06:08:49 +02:00
for ( auto & elem : sc - > affectedCres )
2014-11-26 23:27:38 +02:00
{
2017-07-20 06:08:49 +02:00
auto stack = curInt - > cb - > battleGetStackByID ( elem , false ) ;
if ( stack )
displaySpellEffect ( spellID , stack - > getPosition ( ) ) ;
2015-09-14 04:45:05 +02:00
}
2015-02-07 10:13:24 +02:00
2015-09-14 05:21:49 +02:00
//queuing additional animation
2017-07-20 06:08:49 +02:00
for ( auto & elem : sc - > customEffects )
2015-09-14 04:45:05 +02:00
{
2017-07-20 06:08:49 +02:00
auto stack = curInt - > cb - > battleGetStackByID ( elem . stack , false ) ;
if ( stack )
2022-11-24 16:30:04 +02:00
effectsController - > displayEffect ( EBattleEffect : : EBattleEffect ( elem . effect ) , stack - > getPosition ( ) ) ;
2014-11-26 23:27:38 +02:00
}
2011-12-14 00:35:28 +03:00
waitForAnims ( ) ;
//mana absorption
2016-10-28 23:37:20 +02:00
if ( sc - > manaGained > 0 )
2011-12-14 00:35:28 +03:00
{
2011-12-22 16:05:19 +03:00
Point leftHero = Point ( 15 , 30 ) + pos ;
Point rightHero = Point ( 755 , 30 ) + pos ;
2022-12-01 22:06:42 +02:00
stacksController - > addNewAnim ( new CPointEffectAnimation ( this , soundBase : : invalid , sc - > side ? " SP07_A.DEF " : " SP07_B.DEF " , leftHero ) ) ;
stacksController - > addNewAnim ( new CPointEffectAnimation ( this , soundBase : : invalid , sc - > side ? " SP07_B.DEF " : " SP07_A.DEF " , rightHero ) ) ;
2009-01-15 19:01:08 +02:00
}
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : battleStacksEffectsSet ( const SetStackEffect & sse )
2009-01-15 19:01:08 +02:00
{
2022-11-20 19:11:34 +02:00
if ( stacksController - > getActiveStack ( ) ! = nullptr )
fieldController - > redrawBackgroundWithHexes ( ) ;
2011-12-14 00:35:28 +03:00
}
2011-05-26 17:47:45 +03:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : setHeroAnimation ( ui8 side , int phase )
2017-09-27 16:35:30 +02:00
{
if ( side = = BattleSide : : ATTACKER )
2017-10-07 23:04:43 +02:00
{
if ( attackingHero )
attackingHero - > setPhase ( phase ) ;
}
2017-09-27 16:35:30 +02:00
else
2017-10-07 23:04:43 +02:00
{
if ( defendingHero )
defendingHero - > setPhase ( phase ) ;
}
2017-09-27 16:35:30 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : displayBattleLog ( const std : : vector < MetaString > & battleLog )
2017-07-20 06:08:49 +02:00
{
for ( const auto & line : battleLog )
{
std : : string formatted = line . toString ( ) ;
boost : : algorithm : : trim ( formatted ) ;
2022-11-18 17:54:10 +02:00
if ( ! controlPanel - > console - > addText ( formatted ) )
2017-07-20 06:08:49 +02:00
logGlobal - > warn ( " Too long battle log line " ) ;
}
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : displaySpellAnimationQueue ( const CSpell : : TAnimationQueue & q , BattleHex destinationTile , bool isHit )
2015-03-22 15:47:20 +02:00
{
2021-02-20 03:57:50 +02:00
for ( const CSpell : : TAnimation & animation : q )
2015-03-22 15:47:20 +02:00
{
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
if ( animation . pause > 0 )
2022-11-20 19:11:34 +02:00
stacksController - > addNewAnim ( new CDummyAnimation ( this , animation . pause ) ) ;
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
else
2022-12-01 22:06:42 +02:00
{
2022-12-02 01:55:09 +02:00
int flags = 0 ;
if ( isHit )
flags | = CPointEffectAnimation : : FORCE_ON_TOP ;
if ( animation . verticalPosition = = VerticalPosition : : BOTTOM )
flags | = CPointEffectAnimation : : ALIGN_TO_BOTTOM ;
if ( ! destinationTile . isValid ( ) )
flags | = CPointEffectAnimation : : SCREEN_FILL ;
2022-12-01 22:06:42 +02:00
if ( ! destinationTile . isValid ( ) )
2022-12-02 01:55:09 +02:00
stacksController - > addNewAnim ( new CPointEffectAnimation ( this , soundBase : : invalid , animation . resourceName , flags ) ) ;
2022-12-01 22:06:42 +02:00
else
2022-12-02 01:55:09 +02:00
stacksController - > addNewAnim ( new CPointEffectAnimation ( this , soundBase : : invalid , animation . resourceName , destinationTile , flags ) ) ;
2022-12-01 22:06:42 +02:00
}
2016-01-26 08:37:55 +02:00
}
2015-03-22 15:47:20 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : displaySpellCast ( SpellID spellID , BattleHex destinationTile )
2014-11-27 23:36:14 +02:00
{
2021-02-20 03:57:50 +02:00
const CSpell * spell = spellID . toSpell ( ) ;
2015-03-22 11:18:58 +02:00
2021-02-20 03:57:50 +02:00
if ( spell )
2022-12-02 01:55:09 +02:00
displaySpellAnimationQueue ( spell - > animationInfo . cast , destinationTile , false ) ;
2021-02-20 03:57:50 +02:00
}
2014-11-27 23:36:14 +02:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : displaySpellEffect ( SpellID spellID , BattleHex destinationTile )
2021-02-20 03:57:50 +02:00
{
const CSpell * spell = spellID . toSpell ( ) ;
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
2021-02-20 03:57:50 +02:00
if ( spell )
2022-12-02 01:55:09 +02:00
displaySpellAnimationQueue ( spell - > animationInfo . affect , destinationTile , false ) ;
2014-11-27 23:36:14 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : displaySpellHit ( SpellID spellID , BattleHex destinationTile )
2014-11-27 23:36:14 +02:00
{
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
const CSpell * spell = spellID . toSpell ( ) ;
2015-03-22 11:18:58 +02:00
2021-02-20 03:57:50 +02:00
if ( spell )
2022-12-02 01:55:09 +02:00
displaySpellAnimationQueue ( spell - > animationInfo . hit , destinationTile , true ) ;
2014-11-27 23:36:14 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : setAnimSpeed ( int set )
2011-12-14 00:35:28 +03:00
{
2012-01-12 18:23:00 +03:00
Settings speed = settings . write [ " battle " ] [ " animationSpeed " ] ;
2013-07-06 19:10:20 +03:00
speed - > Float ( ) = float ( set ) / 100 ;
2011-12-14 00:35:28 +03:00
}
2011-02-23 05:57:45 +02:00
2022-12-09 13:26:17 +02:00
int BattleInterface : : getAnimSpeed ( ) const
2011-12-14 00:35:28 +03:00
{
2017-06-03 07:25:10 +02:00
if ( settings [ " session " ] [ " spectate " ] . Bool ( ) & & ! settings [ " session " ] [ " spectate-battle-speed " ] . isNull ( ) )
2020-10-01 10:38:06 +02:00
return static_cast < int > ( vstd : : round ( settings [ " session " ] [ " spectate-battle-speed " ] . Float ( ) * 100 ) ) ;
2017-06-03 07:25:10 +02:00
2020-10-01 10:38:06 +02:00
return static_cast < int > ( vstd : : round ( settings [ " battle " ] [ " animationSpeed " ] . Float ( ) * 100 ) ) ;
2013-07-06 19:10:20 +03:00
}
2022-12-09 13:26:17 +02:00
CPlayerInterface * BattleInterface : : getCurrentPlayerInterface ( ) const
2013-11-03 19:44:47 +03:00
{
return curInt . get ( ) ;
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : trySetActivePlayer ( PlayerColor player )
2013-07-06 19:10:20 +03:00
{
2022-11-20 19:11:34 +02:00
if ( attackerInt & & attackerInt - > playerID = = player )
curInt = attackerInt ;
2013-07-21 13:10:38 +03:00
2022-11-20 19:11:34 +02:00
if ( defenderInt & & defenderInt - > playerID = = player )
curInt = defenderInt ;
2009-09-20 15:47:40 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : activateStack ( )
2009-09-20 15:47:40 +03:00
{
2019-03-22 22:39:53 +02:00
if ( ! battleActionsStarted )
return ; //"show" function should re-call this function
2022-11-20 19:11:34 +02:00
stacksController - > activateStack ( ) ;
2013-11-02 23:07:45 +03:00
2022-11-20 19:11:34 +02:00
const CStack * s = stacksController - > getActiveStack ( ) ;
2022-11-03 20:01:20 +02:00
if ( ! s )
return ;
2009-09-24 16:23:52 +03:00
2022-11-20 19:11:34 +02:00
myTurn = true ;
2011-12-14 00:35:28 +03:00
queue - > update ( ) ;
2022-11-20 19:11:34 +02:00
fieldController - > redrawBackgroundWithHexes ( ) ;
2022-11-20 22:56:42 +02:00
actionsController - > activateStack ( ) ;
2012-05-05 00:16:39 +03:00
GH . fakeMouseMove ( ) ;
2011-12-14 00:35:28 +03:00
}
2009-09-20 15:47:40 +03:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : endAction ( const BattleAction * action )
2012-02-16 20:10:58 +03:00
{
2016-10-28 23:37:20 +02:00
const CStack * stack = curInt - > cb - > battleGetStackByID ( action - > stackNumber ) ;
2013-05-19 18:14:23 +03:00
2017-07-20 06:08:49 +02:00
if ( action - > actionType = = EActionType : : HERO_SPELL )
2022-12-01 22:06:42 +02:00
setHeroAnimation ( action - > side , CCreatureAnim : : HERO_HOLDING ) ;
2012-05-05 00:16:39 +03:00
2022-11-20 19:11:34 +02:00
stacksController - > endAction ( action ) ;
2009-01-15 19:01:08 +02:00
2011-12-14 00:35:28 +03:00
queue - > update ( ) ;
2016-10-28 23:37:20 +02:00
if ( tacticsMode ) //stack ended movement in tactics phase -> select the next one
2022-11-18 17:54:10 +02:00
tacticNextStack ( stack ) ;
2012-04-03 02:23:14 +03:00
2017-07-20 06:08:49 +02:00
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
2022-11-20 19:11:34 +02:00
fieldController - > redrawBackgroundWithHexes ( ) ;
// if (stacksController->getActiveStack() && !animsAreDisplayed.get() && pendingAnims.empty() && !active)
// {
// logGlobal->warn("Something wrong... interface was deactivated but there is no animation. Reactivating...");
// controlPanel->blockUI(false);
// }
// else
// {
2013-07-21 13:10:38 +03:00
// block UI if no active stack (e.g. enemy turn);
2022-11-20 19:11:34 +02:00
controlPanel - > blockUI ( stacksController - > getActiveStack ( ) = = nullptr ) ;
// }
2009-01-15 19:01:08 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : hideQueue ( )
2009-01-15 19:01:08 +02:00
{
2012-01-12 18:23:00 +03:00
Settings showQueue = settings . write [ " battle " ] [ " showQueue " ] ;
showQueue - > Bool ( ) = false ;
2011-12-14 00:35:28 +03:00
queue - > deactivate ( ) ;
2016-10-28 23:37:20 +02:00
if ( ! queue - > embedded )
2009-01-15 19:01:08 +02:00
{
2011-12-22 16:05:19 +03:00
moveBy ( Point ( 0 , - queue - > pos . h / 2 ) ) ;
2011-12-14 00:35:28 +03:00
GH . totalRedraw ( ) ;
2009-01-15 19:01:08 +02:00
}
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : showQueue ( )
2009-01-15 19:01:08 +02:00
{
2012-01-12 18:23:00 +03:00
Settings showQueue = settings . write [ " battle " ] [ " showQueue " ] ;
showQueue - > Bool ( ) = true ;
2009-01-15 19:01:08 +02:00
2011-12-14 00:35:28 +03:00
queue - > activate ( ) ;
2009-01-15 19:01:08 +02:00
2016-10-28 23:37:20 +02:00
if ( ! queue - > embedded )
2011-12-14 00:35:28 +03:00
{
2011-12-22 16:05:19 +03:00
moveBy ( Point ( 0 , + queue - > pos . h / 2 ) ) ;
2011-12-14 00:35:28 +03:00
GH . totalRedraw ( ) ;
}
2009-01-15 19:01:08 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : startAction ( const BattleAction * action )
2009-01-15 19:01:08 +02:00
{
2022-11-18 17:54:10 +02:00
controlPanel - > blockUI ( true ) ;
2013-07-06 19:10:20 +03:00
2017-07-20 06:08:49 +02:00
if ( action - > actionType = = EActionType : : END_TACTIC_PHASE )
2009-01-15 19:01:08 +02:00
{
2022-11-18 17:54:10 +02:00
controlPanel - > tacticPhaseEnded ( ) ;
2011-12-14 00:35:28 +03:00
return ;
2009-01-15 19:01:08 +02:00
}
2011-12-14 00:35:28 +03:00
const CStack * stack = curInt - > cb - > battleGetStackByID ( action - > stackNumber ) ;
2016-10-28 23:37:20 +02:00
if ( stack )
2009-01-15 19:01:08 +02:00
{
2011-12-14 00:35:28 +03:00
queue - > update ( ) ;
2009-01-15 19:01:08 +02:00
}
2011-12-14 00:35:28 +03:00
else
2009-01-15 19:01:08 +02:00
{
2017-07-20 06:08:49 +02:00
assert ( action - > actionType = = EActionType : : HERO_SPELL ) ; //only cast spell is valid action without acting stack number
2009-01-15 19:01:08 +02:00
}
2022-11-20 19:11:34 +02:00
stacksController - > startAction ( action ) ;
2010-08-30 02:12:34 +03:00
2013-07-15 11:51:48 +03:00
redraw ( ) ; // redraw after deactivation, including proper handling of hovered hexes
2011-12-14 00:35:28 +03:00
2017-07-20 06:08:49 +02:00
if ( action - > actionType = = EActionType : : HERO_SPELL ) //when hero casts spell
2011-12-14 00:35:28 +03:00
{
2022-12-01 22:06:42 +02:00
setHeroAnimation ( action - > side , CCreatureAnim : : HERO_CAST_SPELL ) ;
2011-12-14 00:35:28 +03:00
return ;
2010-08-30 02:12:34 +03:00
}
2017-09-27 16:35:30 +02:00
2016-10-28 23:37:20 +02:00
if ( ! stack )
2010-08-30 02:12:34 +03:00
{
2017-08-11 13:38:10 +02:00
logGlobal - > error ( " Something wrong with stackNumber in actionStarted. Stack number: %d " , action - > stackNumber ) ;
2011-12-14 00:35:28 +03:00
return ;
2009-01-15 19:01:08 +02:00
}
2022-11-24 16:30:04 +02:00
effectsController - > startAction ( action ) ;
2011-12-14 00:35:28 +03:00
}
2011-01-08 21:38:42 +02:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : waitForAnims ( )
2011-12-14 00:35:28 +03:00
{
2016-11-25 21:12:22 +02:00
auto unlockPim = vstd : : makeUnlockGuard ( * CPlayerInterface : : pim ) ;
2011-12-14 00:35:28 +03:00
animsAreDisplayed . waitWhileTrue ( ) ;
2009-01-15 19:01:08 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : tacticPhaseEnd ( )
2009-01-15 19:01:08 +02:00
{
2022-11-20 19:11:34 +02:00
stacksController - > setActiveStack ( nullptr ) ;
2022-11-18 17:54:10 +02:00
controlPanel - > blockUI ( true ) ;
2011-12-14 00:35:28 +03:00
tacticsMode = false ;
2009-01-15 19:01:08 +02:00
}
2011-12-14 00:35:28 +03:00
static bool immobile ( const CStack * s )
2009-01-15 19:01:08 +02:00
{
2011-12-14 00:35:28 +03:00
return ! s - > Speed ( 0 , true ) ; //should bound stacks be immobile?
2009-01-15 19:01:08 +02:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : tacticNextStack ( const CStack * current )
2009-01-15 19:01:08 +02:00
{
2016-10-28 23:37:20 +02:00
if ( ! current )
2022-11-20 19:11:34 +02:00
current = stacksController - > getActiveStack ( ) ;
2012-04-03 02:23:14 +03:00
2012-03-01 14:57:38 +03:00
//no switching stacks when the current one is moving
2012-04-03 02:23:14 +03:00
waitForAnims ( ) ;
2012-03-01 14:57:38 +03:00
2011-12-14 00:35:28 +03:00
TStacks stacksOfMine = tacticianInterface - > cb - > battleGetStacks ( CBattleCallback : : ONLY_MINE ) ;
2016-10-28 23:37:20 +02:00
vstd : : erase_if ( stacksOfMine , & immobile ) ;
if ( stacksOfMine . empty ( ) )
2016-08-09 17:15:58 +02:00
{
2022-11-18 17:54:10 +02:00
tacticPhaseEnd ( ) ;
2016-08-09 17:15:58 +02:00
return ;
}
2013-06-29 16:05:48 +03:00
auto it = vstd : : find ( stacksOfMine , current ) ;
2016-10-28 23:37:20 +02:00
if ( it ! = stacksOfMine . end ( ) & & + + it ! = stacksOfMine . end ( ) )
2011-12-14 00:35:28 +03:00
stackActivated ( * it ) ;
else
stackActivated ( stacksOfMine . front ( ) ) ;
2012-04-04 11:03:52 +03:00
2009-01-15 19:01:08 +02:00
}
2009-08-24 15:55:05 +03:00
2022-12-09 13:26:17 +02:00
void BattleInterface : : obstaclePlaced ( const std : : vector < std : : shared_ptr < const CObstacleInstance > > oi )
2012-05-05 00:16:39 +03:00
{
2022-11-17 19:36:25 +02:00
obstacleController - > obstaclePlaced ( oi ) ;
2012-05-05 00:16:39 +03:00
}
2022-12-09 13:26:17 +02:00
const CGHeroInstance * BattleInterface : : currentHero ( ) const
2012-08-26 12:07:48 +03:00
{
2016-10-28 23:37:20 +02:00
if ( attackingHeroInstance - > tempOwner = = curInt - > playerID )
2012-08-26 12:07:48 +03:00
return attackingHeroInstance ;
else
return defendingHeroInstance ;
}
2022-12-09 13:26:17 +02:00
InfoAboutHero BattleInterface : : enemyHero ( ) const
2012-08-26 12:07:48 +03:00
{
InfoAboutHero ret ;
2016-10-28 23:37:20 +02:00
if ( attackingHeroInstance - > tempOwner = = curInt - > playerID )
2012-08-26 12:07:48 +03:00
curInt - > cb - > getHeroInfo ( defendingHeroInstance , ret ) ;
else
curInt - > cb - > getHeroInfo ( attackingHeroInstance , ret ) ;
return ret ;
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : requestAutofightingAIToTakeAction ( )
2013-06-23 00:47:51 +03:00
{
2013-06-23 14:25:48 +03:00
assert ( curInt - > isAutoFightOn ) ;
2013-06-23 00:47:51 +03:00
2017-07-19 01:06:05 +02:00
boost : : thread aiThread ( [ & ] ( )
2013-06-23 00:47:51 +03:00
{
2022-11-20 19:11:34 +02:00
auto ba = make_unique < BattleAction > ( curInt - > autofightingAI - > activeStack ( stacksController - > getActiveStack ( ) ) ) ;
2013-06-23 00:47:51 +03:00
2022-04-04 09:16:32 +02:00
if ( curInt - > cb - > battleIsFinished ( ) )
{
return ; // battle finished with spellcast
}
2016-10-28 23:37:20 +02:00
if ( curInt - > isAutoFightOn )
2013-06-23 00:47:51 +03:00
{
2016-10-28 23:37:20 +02:00
if ( tacticsMode )
2013-11-09 19:25:20 +03:00
{
// Always end tactics mode. Player interface is blocked currently, so it's not possible that
// the AI can take any action except end tactics phase (AI actions won't be triggered)
//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?
2022-11-20 19:11:34 +02:00
stacksController - > setActiveStack ( nullptr ) ;
2022-11-18 17:54:10 +02:00
controlPanel - > blockUI ( true ) ;
2013-11-09 19:25:20 +03:00
tacticsMode = false ;
}
else
{
2017-06-14 03:53:26 +02:00
givenCommand . setn ( ba . release ( ) ) ;
2013-11-09 19:25:20 +03:00
}
2013-06-23 00:47:51 +03:00
}
2013-06-23 14:25:48 +03:00
else
{
2016-11-25 21:12:22 +02:00
boost : : unique_lock < boost : : recursive_mutex > un ( * CPlayerInterface : : pim ) ;
2013-06-23 14:25:48 +03:00
activateStack ( ) ;
}
2013-06-23 00:47:51 +03:00
} ) ;
2014-03-07 16:21:09 +03:00
2013-06-24 17:35:27 +03:00
aiThread . detach ( ) ;
2013-06-23 00:47:51 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : showAll ( SDL_Surface * to )
2013-07-19 19:35:16 +03:00
{
show ( to ) ;
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : show ( SDL_Surface * to )
2013-07-19 19:35:16 +03:00
{
2022-11-25 16:32:23 +02:00
auto canvas = std : : make_shared < CCanvas > ( to ) ;
2013-07-19 19:35:16 +03:00
assert ( to ) ;
SDL_Rect buf ;
SDL_GetClipRect ( to , & buf ) ;
SDL_SetClipRect ( to , & pos ) ;
+ + animCount ;
2022-12-02 17:49:38 +02:00
fieldController - > renderBattlefield ( canvas ) ;
2013-07-19 19:35:16 +03:00
2019-03-22 22:39:53 +02:00
if ( battleActionsStarted )
2022-11-20 19:11:34 +02:00
stacksController - > updateBattleAnimations ( ) ;
2013-07-19 19:35:16 +03:00
SDL_SetClipRect ( to , & buf ) ; //restoring previous clip_rect
2022-11-27 02:26:02 +02:00
showInterface ( canvas ) ;
2013-07-19 19:35:16 +03:00
2022-11-20 19:11:34 +02:00
//activation of next stack, if any
//TODO: should be moved to the very start of this method?
2022-11-27 15:10:27 +02:00
//activateStack();
2013-07-19 19:35:16 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : collectRenderableObjects ( BattleRenderer & renderer )
2022-11-25 00:26:14 +02:00
{
2016-10-28 23:37:20 +02:00
if ( attackingHero )
2022-12-02 17:49:38 +02:00
{
2022-12-09 13:26:17 +02:00
renderer . insert ( EBattleFieldLayer : : HEROES , BattleHex ( 0 ) , [ this ] ( BattleRenderer : : RendererPtr canvas )
2022-12-02 17:49:38 +02:00
{
attackingHero - > show ( canvas - > getSurface ( ) ) ;
} ) ;
}
2016-10-28 23:37:20 +02:00
if ( defendingHero )
2022-12-02 17:49:38 +02:00
{
2022-12-09 13:26:17 +02:00
renderer . insert ( EBattleFieldLayer : : HEROES , BattleHex ( GameConstants : : BFIELD_WIDTH - 1 ) , [ this ] ( BattleRenderer : : RendererPtr canvas )
2022-12-02 17:49:38 +02:00
{
defendingHero - > show ( canvas - > getSurface ( ) ) ;
} ) ;
}
2013-07-19 19:35:16 +03:00
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : showInterface ( std : : shared_ptr < CCanvas > canvas )
2013-07-19 19:35:16 +03:00
{
//showing in-game console
2022-11-27 02:26:02 +02:00
LOCPLINT - > cingconsole - > show ( canvas - > getSurface ( ) ) ;
controlPanel - > showAll ( canvas - > getSurface ( ) ) ;
2013-07-19 19:35:16 +03:00
Rect posWithQueue = Rect ( pos . x , pos . y , 800 , 600 ) ;
2016-10-28 23:37:20 +02:00
if ( settings [ " battle " ] [ " showQueue " ] . Bool ( ) )
2013-07-19 19:35:16 +03:00
{
2016-10-28 23:37:20 +02:00
if ( ! queue - > embedded )
2013-07-19 19:35:16 +03:00
{
posWithQueue . y - = queue - > pos . h ;
posWithQueue . h + = queue - > pos . h ;
}
2022-11-27 02:26:02 +02:00
queue - > showAll ( canvas - > getSurface ( ) ) ;
2013-07-19 19:35:16 +03:00
}
//printing border around interface
2016-10-28 23:37:20 +02:00
if ( screen - > w ! = 800 | | screen - > h ! = 600 )
2013-07-19 19:35:16 +03:00
{
2022-11-27 02:26:02 +02:00
CMessage : : drawBorder ( curInt - > playerID , canvas - > getSurface ( ) , posWithQueue . w + 28 , posWithQueue . h + 28 , posWithQueue . x - 14 , posWithQueue . y - 15 ) ;
2013-07-19 19:35:16 +03:00
}
}
2022-12-09 13:26:17 +02:00
void BattleInterface : : castThisSpell ( SpellID spellID )
2022-11-20 22:56:42 +02:00
{
actionsController - > castThisSpell ( spellID ) ;
}