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"
2009-01-15 19:01:08 +02:00
# include "CBattleInterface.h"
2011-12-14 00:35:28 +03:00
2014-07-13 20:53:37 +03:00
# include "CBattleAnimations.h"
2022-11-20 22:56:42 +02:00
# include "CBattleActionsController.h"
2014-07-13 20:53:37 +03:00
# include "CBattleInterfaceClasses.h"
# include "CCreatureAnimation.h"
2022-11-17 13:21:03 +02:00
# include "CBattleProjectileController.h"
2022-11-17 19:36:25 +02:00
# include "CBattleObstacleController.h"
2022-11-17 18:50:12 +02:00
# include "CBattleSiegeController.h"
2022-11-17 23:57:51 +02:00
# include "CBattleFieldController.h"
2022-11-18 17:54:10 +02:00
# include "CBattleControlPanel.h"
2022-11-20 19:11:34 +02:00
# include "CBattleStacksController.h"
2014-07-13 20:53:37 +03:00
2013-07-06 19:10:20 +03:00
# include "../CBitmapHandler.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 "../CMT.h"
# include "../CMusicHandler.h"
# include "../CPlayerInterface.h"
# include "../CVideoHandler.h"
# include "../Graphics.h"
2017-09-05 15:44:27 +02:00
# include "../gui/CAnimation.h"
2014-07-13 20:53:37 +03:00
# include "../gui/CCursorHandler.h"
# include "../gui/CGuiHandler.h"
# include "../gui/SDL_Extensions.h"
# include "../windows/CAdvmapInterface.h"
# include "../windows/CCreatureWindow.h"
# include "../windows/CSpellWindow.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"
2014-07-13 20:53:37 +03:00
# include "../../lib/CRandomGenerator.h"
2015-02-02 10:25:26 +02:00
# include "../../lib/spells/CSpellHandler.h"
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
# include "../../lib/spells/ISpellMechanics.h"
# include "../../lib/spells/Problem.h"
2011-12-14 00:35:28 +03:00
# include "../../lib/CTownHandler.h"
2022-06-28 10:05:30 +02:00
# include "../../lib/BattleFieldHandler.h"
2022-09-15 10:06:54 +02:00
# include "../../lib/ObstacleHandler.h"
2014-07-15 10:14:49 +03:00
# include "../../lib/CGameState.h"
2013-04-07 13:48:07 +03:00
# include "../../lib/mapping/CMap.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
2016-11-27 18:13:40 +02:00
CondSh < bool > CBattleInterface : : animsAreDisplayed ( false ) ;
2017-06-14 03:53:26 +02:00
CondSh < BattleAction * > CBattleInterface : : givenCommand ( nullptr ) ;
2009-03-28 20:46:20 +02:00
2016-10-28 23:37:20 +02:00
CBattleInterface : : CBattleInterface ( 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-11-17 13:21:03 +02:00
projectilesController . reset ( new CBattleProjectileController ( this ) ) ;
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 " ;
2018-07-25 00:36:48 +02:00
queue = std : : make_shared < CStackQueue > ( 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
}
queue - > update ( ) ;
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-11-17 18:50:12 +02:00
siegeController . reset ( new CBattleSiegeController ( 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
2011-12-14 00:35:28 +03:00
//preparing menu background and terrain
2022-11-17 23:57:51 +02:00
fieldController . reset ( new CBattleFieldController ( this ) ) ;
2022-11-20 19:11:34 +02:00
stacksController . reset ( new CBattleStacksController ( this ) ) ;
2022-11-20 22:56:42 +02:00
actionsController . reset ( new CBattleActionsController ( this ) ) ;
2009-09-17 15:59:04 +03: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
2018-07-25 00:36:48 +02:00
attackingHero = std : : make_shared < CBattleHero > ( 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
2018-07-25 00:36:48 +02:00
defendingHero = std : : make_shared < CBattleHero > ( 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-11-17 19:36:25 +02:00
obstacleController . reset ( new CBattleObstacleController ( 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-18 17:54:10 +02:00
controlPanel - > blockUI ( settings [ " session " ] [ " spectate " ] . Bool ( ) ) ;
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 ) ;
2009-09-10 14:28:34 +03:00
}
2011-12-14 00:35:28 +03:00
CBattleInterface : : ~ CBattleInterface ( )
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
}
2011-12-14 00:35:28 +03:00
//TODO: play AI tracks if battle was during AI turn
2012-02-16 20:10:58 +03:00
//if (!curInt->makingTurn)
2011-12-14 00:35:28 +03:00
//CCS->musich->playMusicFromSet(CCS->musich->aiMusics, -1);
2012-02-16 20:10:58 +03:00
2016-10-28 23:37:20 +02:00
if ( adventureInt & & adventureInt - > selection )
2011-12-14 00:35:28 +03:00
{
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
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : setPrintStackRange ( bool set )
{
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
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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
2011-12-14 00:35:28 +03:00
void CBattleInterface : : activate ( )
{
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 ( ) ;
}
void CBattleInterface : : deactivate ( )
{
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
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : keyPressed ( const SDL_KeyboardEvent & key )
{
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
}
void CBattleInterface : : mouseMoved ( const SDL_MouseMotionEvent & sEvent )
{
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 ) ;
2009-01-15 19:01:08 +02:00
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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-11-20 19:11:34 +02:00
void CBattleInterface : : 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-11-20 19:11:34 +02:00
void CBattleInterface : : stackAdded ( const CStack * stack )
{
stacksController - > stackAdded ( stack ) ;
2011-12-14 00:35:28 +03:00
}
2017-07-20 06:08:49 +02:00
void CBattleInterface : : 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
}
2016-10-28 23:37:20 +02:00
void CBattleInterface : : 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
}
2016-10-28 23:37:20 +02:00
void CBattleInterface : : 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
}
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
void CBattleInterface : : 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 ) )
setHeroAnimation ( side , 2 ) ;
else if ( killedBySide . at ( side ) < killedBySide . at ( 1 - side ) )
setHeroAnimation ( side , 3 ) ;
2009-11-08 16:44:58 +02:00
}
2009-03-21 18:03:07 +02:00
}
2016-10-28 23:37:20 +02:00
void CBattleInterface : : 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
2011-12-14 00:35:28 +03:00
void CBattleInterface : : newRoundFirst ( int round )
{
waitForAnims ( ) ;
}
2011-01-18 19:23:31 +02:00
2011-12-14 00:35:28 +03:00
void CBattleInterface : : newRound ( int number )
{
2022-11-18 17:54:10 +02:00
controlPanel - > console - > addText ( CGI - > generaltexth - > allTexts [ 412 ] ) ;
2011-12-14 00:35:28 +03:00
}
2017-07-20 06:08:49 +02:00
void CBattleInterface : : 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
2017-07-20 06:08:49 +02:00
void CBattleInterface : : sendCommand ( BattleAction * & command , const CStack * actor )
{
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
}
2017-07-01 10:34:00 +02:00
const CGHeroInstance * CBattleInterface : : 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 ;
}
void CBattleInterface : : hexLclicked ( int whichOne )
{
2022-11-20 22:56:42 +02:00
actionsController - > handleHex ( whichOne , LCLICK ) ;
2009-01-15 19:01:08 +02:00
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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-11-17 18:50:12 +02:00
void CBattleInterface : : gateStateChanged ( const EGateState state )
{
if ( siegeController )
siegeController - > gateStateChanged ( state ) ;
2009-09-15 15:20:11 +03:00
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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
2018-07-25 00:36:48 +02:00
GH . pushInt ( std : : make_shared < CBattleResultWindow > ( * 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
}
2017-09-08 13:25:12 +02:00
void CBattleInterface : : 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 ( ) ;
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
2017-09-08 13:25:12 +02:00
const auto casterStackID = sc - > casterStack ;
const CStack * casterStack = nullptr ;
if ( casterStackID > = 0 )
2014-11-27 20:06:11 +02:00
{
2017-09-08 13:25:12 +02:00
casterStack = curInt - > cb - > battleGetStackByID ( casterStackID ) ;
}
2014-11-27 20:33:57 +02:00
2017-09-08 13:25:12 +02:00
Point srccoord = ( sc - > side ? Point ( 770 , 60 ) : Point ( 30 , 60 ) ) + pos ; //hero position by default
{
if ( casterStack ! = nullptr )
2014-11-27 20:06:11 +02:00
{
2017-07-20 06:08:49 +02:00
srccoord = CClickableHex : : getXYUnitAnim ( casterStack - > getPosition ( ) , casterStack , this ) ;
2017-09-08 13:25:12 +02:00
srccoord . x + = 250 ;
srccoord . y + = 240 ;
2014-11-27 20:06:11 +02:00
}
2014-11-27 20:33:57 +02:00
}
2017-09-08 13:25:12 +02:00
if ( casterStack ! = nullptr & & sc - > activeCast )
{
//todo: custom cast animation for hero
2017-07-20 06:08:49 +02:00
displaySpellCast ( spellID , casterStack - > getPosition ( ) ) ;
2017-09-08 13:25:12 +02:00
2022-11-20 19:11:34 +02:00
stacksController - > addNewAnim ( new CCastAnimation ( this , casterStack , sc - > tile , curInt - > cb - > battleGetStackByPos ( sc - > tile ) ) ) ;
2017-09-08 13:25:12 +02:00
}
waitForAnims ( ) ; //wait for cast animation
2015-03-22 11:18:58 +02:00
2014-11-26 23:27:38 +02:00
//playing projectile animation
2016-10-28 23:37:20 +02:00
if ( sc - > tile . isValid ( ) )
2014-11-27 20:06:11 +02:00
{
2014-11-26 23:27:38 +02:00
Point destcoord = CClickableHex : : getXYUnitAnim ( sc - > tile , curInt - > cb - > battleGetStackByPos ( sc - > tile ) , this ) ; //position attacked by projectile
destcoord . x + = 250 ; destcoord . y + = 240 ;
//animation angle
double angle = atan2 ( static_cast < double > ( destcoord . x - srccoord . x ) , static_cast < double > ( destcoord . y - srccoord . y ) ) ;
bool Vflip = ( angle < 0 ) ;
2016-10-28 23:37:20 +02:00
if ( Vflip )
2014-11-26 23:27:38 +02:00
angle = - angle ;
2015-02-07 10:13:24 +02:00
2017-07-20 06:08:49 +02:00
std : : string animToDisplay = spell - > animationInfo . selectProjectile ( angle ) ;
2015-02-07 10:13:24 +02:00
2017-09-05 19:45:29 +02:00
if ( ! animToDisplay . empty ( ) )
2009-08-26 17:09:55 +03:00
{
2017-09-05 19:45:29 +02:00
//TODO: calculate inside CEffectAnimation
std : : shared_ptr < CAnimation > tmp = std : : make_shared < CAnimation > ( animToDisplay ) ;
tmp - > load ( 0 , 0 ) ;
2018-03-30 13:02:04 +02:00
auto first = tmp - > getImage ( 0 , 0 ) ;
2017-09-05 19:45:29 +02:00
2011-12-14 00:35:28 +03:00
//displaying animation
2013-07-16 21:12:47 +03:00
double diffX = ( destcoord . x - srccoord . x ) * ( destcoord . x - srccoord . x ) ;
double diffY = ( destcoord . y - srccoord . y ) * ( destcoord . y - srccoord . y ) ;
double distance = sqrt ( diffX + diffY ) ;
2012-02-16 20:10:58 +03:00
2020-10-01 10:38:06 +02:00
int steps = static_cast < int > ( distance / AnimationControls : : getSpellEffectSpeed ( ) + 1 ) ;
2017-09-05 19:45:29 +02:00
int dx = ( destcoord . x - srccoord . x - first - > width ( ) ) / steps ;
int dy = ( destcoord . y - srccoord . y - first - > height ( ) ) / steps ;
2011-12-14 00:35:28 +03:00
2022-11-20 19:11:34 +02:00
stacksController - > addNewAnim ( new CEffectAnimation ( this , animToDisplay , srccoord . x , srccoord . y , dx , dy , Vflip ) ) ;
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 )
displayEffect ( 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-11-20 19:11:34 +02:00
stacksController - > addNewAnim ( new CEffectAnimation ( this , sc - > side ? " SP07_A.DEF " : " SP07_B.DEF " , leftHero . x , leftHero . y , 0 , 0 , false ) ) ;
stacksController - > addNewAnim ( new CEffectAnimation ( this , sc - > side ? " SP07_B.DEF " : " SP07_A.DEF " , rightHero . x , rightHero . y , 0 , 0 , false ) ) ;
2009-01-15 19:01:08 +02:00
}
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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
2017-09-27 16:35:30 +02:00
void CBattleInterface : : setHeroAnimation ( ui8 side , int phase )
{
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
}
2017-07-20 06:08:49 +02:00
void CBattleInterface : : displayBattleLog ( const std : : vector < MetaString > & battleLog )
{
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 " ) ;
}
}
void CBattleInterface : : displayCustomEffects ( const std : : vector < CustomEffectInfo > & customEffects )
{
for ( const CustomEffectInfo & one : customEffects )
{
if ( one . sound ! = 0 )
CCS - > soundh - > playSound ( soundBase : : soundID ( one . sound ) ) ;
const CStack * s = curInt - > cb - > battleGetStackByID ( one . stack , false ) ;
if ( s & & one . effect ! = 0 )
displayEffect ( one . effect , s - > getPosition ( ) ) ;
}
}
2017-09-05 19:45:29 +02:00
void CBattleInterface : : displayEffect ( ui32 effect , BattleHex destTile )
2011-12-14 00:35:28 +03:00
{
2017-09-05 19:45:29 +02:00
std : : string customAnim = graphics - > battleACToDef [ effect ] [ 0 ] ;
2022-11-20 19:11:34 +02:00
stacksController - > addNewAnim ( new CEffectAnimation ( this , customAnim , destTile ) ) ;
2011-12-14 00:35:28 +03:00
}
2011-01-14 20:08:01 +02:00
2021-02-20 03:57:50 +02:00
void CBattleInterface : : displaySpellAnimationQueue ( const CSpell : : TAnimationQueue & q , BattleHex destinationTile )
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-11-20 19:11:34 +02:00
stacksController - > addNewAnim ( new CEffectAnimation ( this , animation . resourceName , destinationTile , false , animation . verticalPosition = = VerticalPosition : : BOTTOM ) ) ;
2016-01-26 08:37:55 +02:00
}
2015-03-22 15:47:20 +02:00
}
2021-02-20 03:57:50 +02:00
void CBattleInterface : : 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 )
displaySpellAnimationQueue ( spell - > animationInfo . cast , destinationTile ) ;
}
2014-11-27 23:36:14 +02:00
2021-02-20 03:57:50 +02:00
void CBattleInterface : : displaySpellEffect ( SpellID spellID , BattleHex destinationTile )
{
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 )
displaySpellAnimationQueue ( spell - > animationInfo . affect , destinationTile ) ;
2014-11-27 23:36:14 +02:00
}
2016-09-10 17:56:38 +02:00
void CBattleInterface : : 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 )
displaySpellAnimationQueue ( spell - > animationInfo . hit , destinationTile ) ;
2014-11-27 23:36:14 +02:00
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : battleTriggerEffect ( const BattleTriggerEffect & bte )
{
2017-07-20 06:08:49 +02:00
const CStack * stack = curInt - > cb - > battleGetStackByID ( bte . stackID ) ;
if ( ! stack )
{
logGlobal - > error ( " Invalid stack ID %d " , bte . stackID ) ;
return ;
}
2011-12-14 00:35:28 +03:00
//don't show animation when no HP is regenerated
2017-07-20 06:08:49 +02:00
switch ( bte . effect )
2011-01-14 20:08:01 +02:00
{
2017-07-20 06:08:49 +02:00
//TODO: move to bonus type handler
2011-12-14 00:35:28 +03:00
case Bonus : : HP_REGENERATION :
2017-07-20 06:08:49 +02:00
displayEffect ( 74 , stack - > getPosition ( ) ) ;
2012-04-17 11:46:09 +03:00
CCS - > soundh - > playSound ( soundBase : : REGENER ) ;
2011-12-14 00:35:28 +03:00
break ;
case Bonus : : MANA_DRAIN :
2017-07-20 06:08:49 +02:00
displayEffect ( 77 , stack - > getPosition ( ) ) ;
2011-12-14 00:35:28 +03:00
CCS - > soundh - > playSound ( soundBase : : MANADRAI ) ;
break ;
case Bonus : : POISON :
2017-07-20 06:08:49 +02:00
displayEffect ( 67 , stack - > getPosition ( ) ) ;
2011-12-14 00:35:28 +03:00
CCS - > soundh - > playSound ( soundBase : : POISON ) ;
break ;
case Bonus : : FEAR :
2017-07-20 06:08:49 +02:00
displayEffect ( 15 , stack - > getPosition ( ) ) ;
2011-12-14 00:35:28 +03:00
CCS - > soundh - > playSound ( soundBase : : FEAR ) ;
break ;
2012-01-26 19:48:53 +03:00
case Bonus : : MORALE :
{
std : : string hlp = CGI - > generaltexth - > allTexts [ 33 ] ;
boost : : algorithm : : replace_first ( hlp , " %s " , ( stack - > getName ( ) ) ) ;
2017-07-20 06:08:49 +02:00
displayEffect ( 20 , stack - > getPosition ( ) ) ;
2013-05-04 16:14:23 +03:00
CCS - > soundh - > playSound ( soundBase : : GOODMRLE ) ;
2022-11-18 17:54:10 +02:00
controlPanel - > console - > addText ( hlp ) ;
2012-01-26 19:48:53 +03:00
break ;
}
2011-12-14 00:35:28 +03:00
default :
return ;
2011-01-14 20:08:01 +02:00
}
2011-12-14 00:35:28 +03:00
//waitForAnims(); //fixme: freezes game :?
}
2011-01-14 20:08:01 +02:00
2011-12-14 00:35:28 +03:00
void CBattleInterface : : setAnimSpeed ( int set )
{
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
2011-12-14 00:35:28 +03:00
int CBattleInterface : : getAnimSpeed ( ) const
{
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
}
2016-10-28 23:37:20 +02:00
CPlayerInterface * CBattleInterface : : getCurrentPlayerInterface ( ) const
2013-11-03 19:44:47 +03:00
{
return curInt . get ( ) ;
}
2022-11-20 19:11:34 +02:00
void CBattleInterface : : 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
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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 )
2017-09-27 16:35:30 +02:00
setHeroAnimation ( action - > side , 0 ) ;
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
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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
}
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : 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
}
2011-12-14 00:35:28 +03:00
void CBattleInterface : : startAction ( const BattleAction * action )
2009-01-15 19:01:08 +02:00
{
2013-07-16 21:12:47 +03:00
//setActiveStack(nullptr);
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
{
2017-09-27 16:35:30 +02:00
setHeroAnimation ( action - > side , 4 ) ;
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
}
2011-12-14 00:35:28 +03:00
int txtid = 0 ;
switch ( action - > actionType )
{
2017-07-20 06:08:49 +02:00
case EActionType : : WAIT :
2011-12-14 00:35:28 +03:00
txtid = 136 ;
break ;
2017-07-20 06:08:49 +02:00
case EActionType : : BAD_MORALE :
2011-12-14 00:35:28 +03:00
txtid = - 34 ; //negative -> no separate singular/plural form
2017-07-20 06:08:49 +02:00
displayEffect ( 30 , stack - > getPosition ( ) ) ;
2013-05-04 16:14:23 +03:00
CCS - > soundh - > playSound ( soundBase : : BADMRLE ) ;
2011-12-14 00:35:28 +03:00
break ;
}
2009-01-15 19:01:08 +02:00
2017-07-04 13:24:46 +02:00
if ( txtid ! = 0 )
2022-11-18 17:54:10 +02:00
controlPanel - > console - > addText ( stack - > formatGeneralMessage ( txtid ) ) ;
2009-01-15 19:01:08 +02:00
2011-12-14 00:35:28 +03:00
//displaying special abilities
2022-11-20 19:11:34 +02:00
auto actionTarget = action - > getTarget ( curInt - > cb . get ( ) ) ;
2017-07-04 13:24:46 +02:00
switch ( action - > actionType )
2011-01-08 21:38:42 +02:00
{
2017-07-20 06:08:49 +02:00
case EActionType : : STACK_HEAL :
displayEffect ( 74 , actionTarget . at ( 0 ) . hexValue ) ;
2011-12-14 00:35:28 +03:00
CCS - > soundh - > playSound ( soundBase : : REGENER ) ;
break ;
2011-01-08 21:38:42 +02:00
}
2011-12-14 00:35:28 +03:00
}
2011-01-08 21:38:42 +02:00
2011-12-14 00:35:28 +03:00
void CBattleInterface : : waitForAnims ( )
{
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-11-18 17:54:10 +02:00
void CBattleInterface : : 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-11-18 17:54:10 +02:00
void CBattleInterface : : 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
2012-05-05 00:16:39 +03:00
void CBattleInterface : : obstaclePlaced ( const CObstacleInstance & oi )
{
2022-11-17 19:36:25 +02:00
obstacleController - > obstaclePlaced ( oi ) ;
2012-05-05 00:16:39 +03:00
}
2016-10-28 23:37:20 +02:00
const CGHeroInstance * CBattleInterface : : 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 ;
}
InfoAboutHero CBattleInterface : : enemyHero ( ) const
{
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 ;
}
2013-06-23 00:47:51 +03:00
void CBattleInterface : : requestAutofightingAIToTakeAction ( )
{
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
}
2016-10-28 23:37:20 +02:00
void CBattleInterface : : showAll ( SDL_Surface * to )
2013-07-19 19:35:16 +03:00
{
show ( to ) ;
}
2016-10-28 23:37:20 +02:00
void CBattleInterface : : show ( SDL_Surface * to )
2013-07-19 19:35:16 +03:00
{
assert ( to ) ;
SDL_Rect buf ;
SDL_GetClipRect ( to , & buf ) ;
SDL_SetClipRect ( to , & pos ) ;
+ + animCount ;
2022-11-20 19:11:34 +02:00
if ( stacksController - > getActiveStack ( ) ! = nullptr /*&& creAnims[stacksController->getActiveStack()->ID]->isIdle()*/ ) //show everything with range
2022-11-17 23:57:51 +02:00
{
2022-11-20 19:11:34 +02:00
// FIXME: any *real* reason to keep this separate? Speed difference can't be that big // TODO: move to showAll?
2022-11-17 23:57:51 +02:00
fieldController - > showBackgroundImageWithHexes ( to ) ;
}
else
{
fieldController - > showBackgroundImage ( to ) ;
obstacleController - > showAbsoluteObstacles ( to ) ;
if ( siegeController )
siegeController - > showAbsoluteObstacles ( to ) ;
}
fieldController - > showHighlightedHexes ( to ) ;
2013-07-19 19:35:16 +03:00
showBattlefieldObjects ( to ) ;
2022-11-17 13:21:03 +02:00
projectilesController - > showProjectiles ( to ) ;
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
showInterface ( to ) ;
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?
activateStack ( ) ;
2013-07-19 19:35:16 +03:00
}
2016-10-28 23:37:20 +02:00
void CBattleInterface : : showBattlefieldObjects ( SDL_Surface * to )
2013-07-19 19:35:16 +03:00
{
auto showHexEntry = [ & ] ( BattleObjectsByHex : : HexData & hex )
{
2022-11-17 18:50:12 +02:00
if ( siegeController )
siegeController - > showPiecesOfWall ( to , hex . walls ) ;
2022-11-17 19:36:25 +02:00
obstacleController - > showObstacles ( to , hex . obstacles ) ;
2022-11-20 19:11:34 +02:00
stacksController - > showAliveStacks ( to , hex . alive ) ;
2013-07-19 19:35:16 +03:00
showBattleEffects ( to , hex . effects ) ;
} ;
BattleObjectsByHex objects = sortObjectsByHex ( ) ;
2013-07-21 13:10:38 +03:00
// dead stacks should be blit first
2022-11-20 19:11:34 +02:00
stacksController - > showStacks ( to , objects . beforeAll . dead ) ;
2016-10-30 05:47:33 +02:00
for ( auto & data : objects . hex )
2022-11-20 19:11:34 +02:00
stacksController - > showStacks ( to , data . dead ) ;
stacksController - > showStacks ( to , objects . afterAll . dead ) ;
2013-07-21 13:10:38 +03:00
2013-07-19 19:35:16 +03:00
// display objects that must be blit before anything else (e.g. topmost walls)
showHexEntry ( objects . beforeAll ) ;
2013-09-30 11:45:26 +03:00
// show heroes after "beforeAll" - e.g. topmost wall in siege
2016-10-28 23:37:20 +02:00
if ( attackingHero )
2013-09-30 11:45:26 +03:00
attackingHero - > show ( to ) ;
2016-10-28 23:37:20 +02:00
if ( defendingHero )
2013-09-30 11:45:26 +03:00
defendingHero - > show ( to ) ;
2013-07-19 19:35:16 +03:00
// actual blit of most of objects, hex by hex
// NOTE: row-by-row blitting may be a better approach
2016-10-30 05:47:33 +02:00
for ( auto & data : objects . hex )
2013-07-19 19:35:16 +03:00
showHexEntry ( data ) ;
2016-10-30 05:47:33 +02:00
2013-07-19 19:35:16 +03:00
// objects that must be blit *after* everything else - e.g. bottom tower or some spell effects
showHexEntry ( objects . afterAll ) ;
}
void CBattleInterface : : showBattleEffects ( SDL_Surface * to , const std : : vector < const BattleEffect * > & battleEffects )
{
2016-10-28 23:37:20 +02:00
for ( auto & elem : battleEffects )
2013-07-19 19:35:16 +03:00
{
2020-10-01 10:38:06 +02:00
int currentFrame = static_cast < int > ( floor ( elem - > currentFrame ) ) ;
2017-09-05 16:21:44 +02:00
currentFrame % = elem - > animation - > size ( ) ;
2013-07-19 19:35:16 +03:00
2018-03-30 13:02:04 +02:00
auto img = elem - > animation - > getImage ( currentFrame ) ;
2017-09-05 16:21:44 +02:00
SDL_Rect temp_rect = genRect ( img - > height ( ) , img - > width ( ) , elem - > x , elem - > y ) ;
img - > draw ( to , & temp_rect , nullptr ) ;
2013-07-19 19:35:16 +03:00
}
}
2016-10-28 23:37:20 +02:00
void CBattleInterface : : showInterface ( SDL_Surface * to )
2013-07-19 19:35:16 +03:00
{
//showing in-game console
LOCPLINT - > cingconsole - > show ( to ) ;
2022-11-18 17:54:10 +02:00
controlPanel - > show ( to ) ;
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 ;
}
2017-07-20 06:08:49 +02:00
queue - > showAll ( to ) ;
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
{
CMessage : : drawBorder ( curInt - > playerID , to , posWithQueue . w + 28 , posWithQueue . h + 28 , posWithQueue . x - 14 , posWithQueue . y - 15 ) ;
}
}
BattleObjectsByHex CBattleInterface : : sortObjectsByHex ( )
{
BattleObjectsByHex sorted ;
// Sort creatures
2022-11-20 19:11:34 +02:00
stacksController - > sortObjectsByHex ( sorted ) ;
2013-07-19 19:35:16 +03:00
// Sort battle effects (spells)
for ( auto & battleEffect : battleEffects )
{
2016-10-28 23:37:20 +02:00
if ( battleEffect . position . isValid ( ) )
2013-07-19 19:35:16 +03:00
sorted . hex [ battleEffect . position ] . effects . push_back ( & battleEffect ) ;
else
sorted . afterAll . effects . push_back ( & battleEffect ) ;
}
// Sort obstacles
2022-11-17 19:36:25 +02:00
obstacleController - > sortObjectsByHex ( sorted ) ;
2013-07-19 19:35:16 +03:00
// Sort wall parts
2022-11-17 18:50:12 +02:00
if ( siegeController )
siegeController - > sortObjectsByHex ( sorted ) ;
2013-10-27 16:05:01 +03:00
2013-07-19 19:35:16 +03:00
return sorted ;
}
2022-11-20 22:56:42 +02:00
void CBattleInterface : : castThisSpell ( SpellID spellID )
{
actionsController - > castThisSpell ( spellID ) ;
}