2018-01-05 20:21:07 +03:00
/*
* CMainMenu . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
# include "StdInc.h"
# include "CMainMenu.h"
# include "CCampaignScreen.h"
# include "CreditsScreen.h"
2023-09-22 01:39:35 +02:00
# include "CHighScoreScreen.h"
2018-01-05 20:21:07 +03:00
# include "../lobby/CBonusSelection.h"
# include "../lobby/CSelectionBase.h"
# include "../lobby/CLobbyScreen.h"
2024-05-02 15:55:20 +03:00
# include "../media/IMusicPlayer.h"
2024-09-12 22:28:45 +02:00
# include "../media/IVideoPlayer.h"
2023-01-05 19:34:37 +02:00
# include "../gui/CursorHandler.h"
2018-01-05 20:21:07 +03:00
# include "../windows/GUIClasses.h"
2025-02-10 21:49:23 +00:00
# include "../GameEngine.h"
2025-02-11 15:23:33 +00:00
# include "../GameInstance.h"
2025-02-10 21:49:23 +00:00
# include "../eventsSDL/InputHandler.h"
2023-04-27 20:21:06 +03:00
# include "../gui/ShortcutHandler.h"
# include "../gui/Shortcut.h"
2023-05-16 15:10:26 +03:00
# include "../gui/WindowHandler.h"
2023-06-02 16:42:18 +03:00
# include "../render/Canvas.h"
2023-12-28 21:27:21 +02:00
# include "../globalLobby/GlobalLobbyLoginWindow.h"
# include "../globalLobby/GlobalLobbyClient.h"
2023-12-27 19:07:49 +02:00
# include "../globalLobby/GlobalLobbyWindow.h"
2018-01-05 20:21:07 +03:00
# include "../widgets/CComponent.h"
# include "../widgets/Buttons.h"
2024-05-12 10:24:13 +00:00
# include "../widgets/CTextInput.h"
2018-01-05 20:21:07 +03:00
# include "../widgets/MiscWidgets.h"
# include "../widgets/ObjectLists.h"
# include "../widgets/TextControls.h"
2024-05-02 22:14:50 +03:00
# include "../widgets/VideoWidget.h"
2018-01-05 20:21:07 +03:00
# include "../windows/InfoWindows.h"
# include "../CServerHandler.h"
2023-02-02 21:15:13 +02:00
# include "../CPlayerInterface.h"
# include "../Client.h"
2023-02-03 18:23:53 +02:00
# include "../CMT.h"
2023-02-02 21:15:13 +02:00
2024-07-20 12:55:17 +00:00
# include "../../lib/texts/CGeneralTextHandler.h"
2023-06-25 22:28:24 +03:00
# include "../../lib/campaign/CampaignHandler.h"
2023-02-02 21:15:13 +02:00
# include "../../lib/filesystem/Filesystem.h"
# include "../../lib/filesystem/CCompressedStream.h"
2023-08-09 03:54:09 +04:00
# include "../../lib/mapping/CMapInfo.h"
2023-11-15 17:57:40 +02:00
# include "../../lib/modding/CModHandler.h"
2023-02-02 21:15:13 +02:00
# include "../../lib/VCMIDirs.h"
2018-01-05 20:21:07 +03:00
# include "../../lib/CStopWatch.h"
# include "../../lib/CThreadHelper.h"
# include "../../lib/CConfigHandler.h"
# include "../../lib/GameConstants.h"
# include "../../lib/CRandomGenerator.h"
2025-02-14 16:23:37 +00:00
# include "../../lib/GameLibrary.h"
2025-03-11 20:04:31 +01:00
# include "../../lib/json/JsonUtils.h"
2018-01-05 20:21:07 +03:00
2025-03-18 14:37:22 +00:00
# include <boost/lexical_cast.hpp>
2024-06-11 14:12:03 +00:00
ISelectionScreenInfo * SEL = nullptr ;
2018-01-05 20:21:07 +03:00
CMenuScreen : : CMenuScreen ( const JsonNode & configNode )
: CWindowObject ( BORDERED ) , config ( configNode )
{
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2018-01-05 20:21:07 +03:00
2025-01-06 11:33:15 +01:00
const auto & bgConfig = config [ " background " ] ;
2025-03-07 14:11:43 +01:00
if ( bgConfig . isVector ( ) )
2025-01-06 11:33:15 +01:00
background = std : : make_shared < CPicture > ( ImagePath : : fromJson ( * RandomGeneratorUtil : : nextItem ( bgConfig . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) ) ;
if ( bgConfig . isString ( ) )
background = std : : make_shared < CPicture > ( ImagePath : : fromJson ( bgConfig ) ) ;
2018-01-05 20:21:07 +03:00
if ( config [ " scalable " ] . Bool ( ) )
2025-02-10 21:49:23 +00:00
background - > scaleTo ( ENGINE - > screenDimensions ( ) ) ;
2018-01-05 20:21:07 +03:00
pos = background - > center ( ) ;
2025-03-07 17:16:17 +01:00
for ( const JsonNode & node : config [ " images " ] . Vector ( ) )
{
auto image = std : : make_shared < CPicture > ( ImagePath : : fromJson ( * RandomGeneratorUtil : : nextItem ( node [ " name " ] . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) , Point ( node [ " x " ] . Integer ( ) , node [ " y " ] . Integer ( ) ) ) ;
images . push_back ( image ) ;
2025-01-31 14:20:10 +01:00
}
2024-08-29 12:37:11 +00:00
if ( ! config [ " video " ] . isNull ( ) )
{
Point videoPosition ( config [ " video " ] [ " x " ] . Integer ( ) , config [ " video " ] [ " y " ] . Integer ( ) ) ;
videoPlayer = std : : make_shared < VideoWidget > ( videoPosition , VideoPath : : fromJson ( config [ " video " ] [ " name " ] ) , false ) ;
}
2018-01-05 20:21:07 +03:00
for ( const JsonNode & node : config [ " items " ] . Vector ( ) )
menuNameToEntry . push_back ( node [ " name " ] . String ( ) ) ;
//Hardcoded entry
menuNameToEntry . push_back ( " credits " ) ;
2018-04-07 14:34:11 +03:00
tabs = std : : make_shared < CTabbedInt > ( std : : bind ( & CMenuScreen : : createTab , this , _1 ) ) ;
2024-08-29 12:37:11 +00:00
if ( config [ " video " ] . isNull ( ) )
2023-09-26 21:12:04 +02:00
tabs - > setRedrawParent ( true ) ;
2024-05-02 22:14:50 +03:00
2018-01-05 20:21:07 +03:00
}
2018-04-07 14:34:11 +03:00
std : : shared_ptr < CIntObject > CMenuScreen : : createTab ( size_t index )
2018-01-05 20:21:07 +03:00
{
if ( config [ " items " ] . Vector ( ) . size ( ) = = index )
2018-04-07 18:42:11 +07:00
return std : : make_shared < CreditsScreen > ( this - > pos ) ;
2018-04-07 14:34:11 +03:00
else
return std : : make_shared < CMenuEntry > ( this , config [ " items " ] . Vector ( ) [ index ] ) ;
2018-01-05 20:21:07 +03:00
}
2024-05-15 16:34:23 +00:00
void CMenuScreen : : show ( Canvas & to )
{
// TODO: avoid excessive redraws
CIntObject : : showAll ( to ) ;
}
2018-01-05 20:21:07 +03:00
void CMenuScreen : : activate ( )
{
CIntObject : : activate ( ) ;
}
void CMenuScreen : : switchToTab ( size_t index )
{
tabs - > setActive ( index ) ;
}
2018-04-07 18:42:11 +07:00
void CMenuScreen : : switchToTab ( std : : string name )
{
switchToTab ( vstd : : find_pos ( menuNameToEntry , name ) ) ;
}
2021-01-17 19:16:34 +03:00
size_t CMenuScreen : : getActiveTab ( ) const
{
return tabs - > getActive ( ) ;
}
2024-06-24 03:23:26 +02:00
//function for std::string -> std::function conversion for main menu
2018-01-05 20:21:07 +03:00
static std : : function < void ( ) > genCommand ( CMenuScreen * menu , std : : vector < std : : string > menuType , const std : : string & string )
{
static const std : : vector < std : : string > commandType = { " to " , " campaigns " , " start " , " load " , " exit " , " highscores " } ;
static const std : : vector < std : : string > gameType = { " single " , " multi " , " campaign " , " tutorial " } ;
std : : list < std : : string > commands ;
boost : : split ( commands , string , boost : : is_any_of ( " \t " ) ) ;
if ( ! commands . empty ( ) )
{
size_t index = std : : find ( commandType . begin ( ) , commandType . end ( ) , commands . front ( ) ) - commandType . begin ( ) ;
commands . pop_front ( ) ;
if ( index > 3 | | ! commands . empty ( ) )
{
switch ( index )
{
case 0 : //to - switch to another tab, if such tab exists
{
size_t index2 = std : : find ( menuType . begin ( ) , menuType . end ( ) , commands . front ( ) ) - menuType . begin ( ) ;
if ( index2 ! = menuType . size ( ) )
2018-04-07 18:42:11 +07:00
return std : : bind ( ( void ( CMenuScreen : : * ) ( size_t ) ) & CMenuScreen : : switchToTab , menu , index2 ) ;
2018-01-05 20:21:07 +03:00
break ;
}
case 1 : //open campaign selection window
{
2025-02-27 22:42:29 +00:00
return std : : bind ( & CMainMenu : : openCampaignScreen , GAME - > mainmenu ( ) , commands . front ( ) ) ;
2018-01-05 20:21:07 +03:00
break ;
}
case 2 : //start
{
switch ( std : : find ( gameType . begin ( ) , gameType . end ( ) , commands . front ( ) ) - gameType . begin ( ) )
{
case 0 :
2024-09-03 00:25:35 +02:00
return [ ] ( ) { CMainMenu : : openLobby ( ESelectionScreen : : newGame , true , { } , ELoadMode : : NONE ) ; } ;
2018-01-05 20:21:07 +03:00
case 1 :
2025-02-10 21:49:23 +00:00
return [ ] ( ) { ENGINE - > windows ( ) . createAndPushWindow < CMultiMode > ( ESelectionScreen : : newGame ) ; } ;
2018-01-05 20:21:07 +03:00
case 2 :
2024-09-03 00:25:35 +02:00
return [ ] ( ) { CMainMenu : : openLobby ( ESelectionScreen : : campaignList , true , { } , ELoadMode : : NONE ) ; } ;
2018-01-05 20:21:07 +03:00
case 3 :
2024-09-03 00:25:35 +02:00
return [ ] ( ) { CMainMenu : : startTutorial ( ) ; } ;
2018-01-05 20:21:07 +03:00
}
break ;
}
case 3 : //load
{
switch ( std : : find ( gameType . begin ( ) , gameType . end ( ) , commands . front ( ) ) - gameType . begin ( ) )
{
case 0 :
2024-09-03 00:25:35 +02:00
return [ ] ( ) { CMainMenu : : openLobby ( ESelectionScreen : : loadGame , true , { } , ELoadMode : : SINGLE ) ; } ;
2018-01-05 20:21:07 +03:00
case 1 :
2025-02-10 21:49:23 +00:00
return [ ] ( ) { ENGINE - > windows ( ) . createAndPushWindow < CMultiMode > ( ESelectionScreen : : loadGame ) ; } ;
2018-01-05 20:21:07 +03:00
case 2 :
2024-09-03 00:25:35 +02:00
return [ ] ( ) { CMainMenu : : openLobby ( ESelectionScreen : : loadGame , true , { } , ELoadMode : : CAMPAIGN ) ; } ;
2018-01-05 20:21:07 +03:00
case 3 :
2024-09-03 00:25:35 +02:00
return [ ] ( ) { CMainMenu : : openLobby ( ESelectionScreen : : loadGame , true , { } , ELoadMode : : TUTORIAL ) ; } ;
2024-01-21 16:48:36 +02:00
2018-01-05 20:21:07 +03:00
}
}
break ;
case 4 : //exit
{
2025-03-03 21:45:58 +00:00
return [ ] ( ) { CInfoWindow : : showYesNoDialog ( LIBRARY - > generaltexth - > allTexts [ 69 ] , std : : vector < std : : shared_ptr < CComponent > > ( ) , [ ] ( ) { GAME - > onShutdownRequested ( false ) ; } , 0 , PlayerColor ( 1 ) ) ; } ;
2018-01-05 20:21:07 +03:00
}
break ;
case 5 : //highscores
{
2024-09-03 00:25:35 +02:00
return [ ] ( ) { CMainMenu : : openHighScoreScreen ( ) ; } ;
2018-01-05 20:21:07 +03:00
}
}
}
}
logGlobal - > error ( " Failed to parse command: %s " , string ) ;
return std : : function < void ( ) > ( ) ;
}
std : : shared_ptr < CButton > CMenuEntry : : createButton ( CMenuScreen * parent , const JsonNode & button )
{
std : : function < void ( ) > command = genCommand ( parent , parent - > menuNameToEntry , button [ " command " ] . String ( ) ) ;
std : : pair < std : : string , std : : string > help ;
if ( ! button [ " help " ] . isNull ( ) & & button [ " help " ] . Float ( ) > 0 )
2025-02-14 16:23:37 +00:00
help = LIBRARY - > generaltexth - > zelp [ ( size_t ) button [ " help " ] . Float ( ) ] ;
2018-01-05 20:21:07 +03:00
2020-10-01 01:38:06 -07:00
int posx = static_cast < int > ( button [ " x " ] . Float ( ) ) ;
2018-01-05 20:21:07 +03:00
if ( posx < 0 )
posx = pos . w + posx ;
2020-10-01 01:38:06 -07:00
int posy = static_cast < int > ( button [ " y " ] . Float ( ) ) ;
2018-01-05 20:21:07 +03:00
if ( posy < 0 )
posy = pos . h + posy ;
2025-02-10 21:49:23 +00:00
EShortcut shortcut = ENGINE - > shortcuts ( ) . findShortcut ( button [ " shortcut " ] . String ( ) ) ;
2023-04-27 20:21:06 +03:00
2024-04-11 22:00:54 +03:00
if ( shortcut = = EShortcut : : NONE & & ! button [ " shortcut " ] . String ( ) . empty ( ) )
logGlobal - > warn ( " Unknown shortcut '%s' found when loading main menu config! " , button [ " shortcut " ] . String ( ) ) ;
2023-08-23 15:07:50 +03:00
auto result = std : : make_shared < CButton > ( Point ( posx , posy ) , AnimationPath : : fromJson ( button [ " name " ] ) , help , command , shortcut ) ;
2022-12-27 16:53:46 +02:00
if ( button [ " center " ] . Bool ( ) )
result - > moveBy ( Point ( - result - > pos . w / 2 , - result - > pos . h / 2 ) ) ;
2025-03-07 17:16:17 +01:00
2022-12-27 16:53:46 +02:00
return result ;
2018-01-05 20:21:07 +03:00
}
CMenuEntry : : CMenuEntry ( CMenuScreen * parent , const JsonNode & config )
{
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2023-07-03 19:24:12 +03:00
setRedrawParent ( true ) ;
2018-01-05 20:21:07 +03:00
pos = parent - > pos ;
for ( const JsonNode & node : config [ " images " ] . Vector ( ) )
images . push_back ( CMainMenu : : createPicture ( node ) ) ;
2025-03-03 17:38:54 +01:00
for ( const JsonNode & node : config [ " buttons " ] . Vector ( ) )
{
2025-01-12 11:35:06 +01:00
auto tokens = node [ " command " ] . String ( ) . find ( ' ' ) ;
std : : pair < std : : string , std : : string > commandParts = {
node [ " command " ] . String ( ) . substr ( 0 , tokens ) ,
( tokens = = std : : string : : npos ) ? " " : node [ " command " ] . String ( ) . substr ( tokens + 1 )
} ;
2025-03-03 17:38:54 +01:00
if ( commandParts . first = = " campaigns " )
{
2025-01-12 11:35:06 +01:00
const auto & campaign = CMainMenuConfig : : get ( ) . getCampaigns ( ) [ commandParts . second ] ;
2025-03-03 17:38:54 +01:00
if ( ! campaign . isStruct ( ) )
{
2025-01-12 11:35:06 +01:00
logGlobal - > warn ( " Campaign set %s not found " , commandParts . second ) ;
continue ;
}
bool fileExists = false ;
2025-03-03 17:38:54 +01:00
for ( const auto & item : campaign [ " items " ] . Vector ( ) )
{
2025-01-12 11:35:06 +01:00
std : : string filename = item [ " file " ] . String ( ) ;
2025-03-03 17:38:54 +01:00
if ( CResourceHandler : : get ( ) - > existsResource ( ResourcePath ( filename , EResType : : CAMPAIGN ) ) )
{
2025-01-12 11:35:06 +01:00
fileExists = true ;
break ;
}
}
2025-03-03 17:38:54 +01:00
if ( ! fileExists )
{
2025-01-12 11:35:06 +01:00
logGlobal - > warn ( " No valid files found for campaign set %s " , commandParts . second ) ;
continue ;
}
}
2018-01-05 20:21:07 +03:00
buttons . push_back ( createButton ( parent , node ) ) ;
2024-02-27 22:19:09 +02:00
buttons . back ( ) - > setHoverable ( true ) ;
2023-07-03 19:24:12 +03:00
buttons . back ( ) - > setRedrawParent ( true ) ;
2018-01-05 20:21:07 +03:00
}
}
CMainMenuConfig : : CMainMenuConfig ( )
2025-03-11 20:04:31 +01:00
: campaignSets ( JsonUtils : : assembleFromFiles ( " config/campaignSets.json " ) )
2023-09-02 00:26:14 +03:00
, config ( JsonPath : : builtin ( " config/mainmenu.json " ) )
2018-01-05 20:21:07 +03:00
{
2025-01-31 14:20:10 +01:00
if ( ! config [ " scenario-selection " ] . isStruct ( ) )
2025-03-03 17:38:54 +01:00
// Fallback for 1.6 mods
if ( config [ " game-select " ] . Vector ( ) . empty ( ) )
handleFatalError ( " The main menu configuration file mainmenu.json is invalid or corrupted. Please check the file for errors, verify your mod setup, or reinstall VCMI to resolve the issue. " , false ) ;
2018-01-05 20:21:07 +03:00
}
2024-02-12 13:22:54 +02:00
const CMainMenuConfig & CMainMenuConfig : : get ( )
2018-01-05 20:21:07 +03:00
{
2024-02-12 13:22:54 +02:00
static const CMainMenuConfig config ;
2018-01-05 20:21:07 +03:00
return config ;
}
const JsonNode & CMainMenuConfig : : getConfig ( ) const
{
return config ;
}
const JsonNode & CMainMenuConfig : : getCampaigns ( ) const
{
return campaignSets ;
}
2024-09-18 22:10:25 +02:00
CMainMenu : : CMainMenu ( )
2018-01-05 20:21:07 +03:00
{
2025-02-10 21:49:23 +00:00
pos . w = ENGINE - > screenDimensions ( ) . x ;
pos . h = ENGINE - > screenDimensions ( ) . y ;
2018-01-05 20:21:07 +03:00
2018-07-25 01:36:48 +03:00
menu = std : : make_shared < CMenuScreen > ( CMainMenuConfig : : get ( ) . getConfig ( ) [ " window " ] ) ;
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2023-08-23 15:07:50 +03:00
backgroundAroundMenu = std : : make_shared < CFilledTexture > ( ImagePath : : builtin ( " DIBOXBCK " ) , pos ) ;
2024-09-12 23:23:00 +02:00
}
2025-02-27 22:18:31 +00:00
CMainMenu : : ~ CMainMenu ( ) = default ;
2024-09-12 23:23:00 +02:00
2024-09-18 22:10:25 +02:00
void CMainMenu : : playIntroVideos ( )
2024-09-12 23:23:00 +02:00
{
2024-09-18 22:10:25 +02:00
auto playVideo = [ ] ( std : : string video , bool rim , float scaleFactor , std : : function < void ( bool ) > cb ) {
2025-02-10 22:08:50 +00:00
if ( ENGINE - > video ( ) . open ( VideoPath : : builtin ( video ) , scaleFactor ) )
2025-02-10 21:49:23 +00:00
ENGINE - > windows ( ) . createAndPushWindow < VideoWindow > ( VideoPath : : builtin ( video ) , rim ? ImagePath : : builtin ( " INTRORIM " ) : ImagePath : : builtin ( " " ) , true , scaleFactor , [ cb ] ( bool skipped ) { cb ( skipped ) ; } ) ;
2024-09-18 22:10:25 +02:00
else
cb ( true ) ;
} ;
playVideo ( " 3DOLOGO.SMK " , false , 1.25 , [ playVideo , this ] ( bool skipped ) {
if ( ! skipped )
playVideo ( " NWCLOGO.SMK " , false , 2 , [ playVideo , this ] ( bool skipped ) {
if ( ! skipped )
playVideo ( " H3INTRO.SMK " , true , 1 , [ this ] ( bool skipped ) {
2024-09-12 23:23:00 +02:00
playMusic ( ) ;
2024-09-18 22:10:25 +02:00
} ) ;
else
playMusic ( ) ;
} ) ;
else
playMusic ( ) ;
} ) ;
}
void CMainMenu : : playMusic ( )
{
2025-02-10 22:08:50 +00:00
ENGINE - > music ( ) . playMusic ( AudioPath : : builtin ( " Music/MainMenu " ) , true , true ) ;
2018-01-05 20:21:07 +03:00
}
2023-05-08 00:59:48 +03:00
void CMainMenu : : activate ( )
{
// check if screen was resized while main menu was inactive - e.g. in gameplay mode
2025-02-10 21:49:23 +00:00
if ( pos . dimensions ( ) ! = ENGINE - > screenDimensions ( ) )
2023-05-08 00:59:48 +03:00
onScreenResize ( ) ;
CIntObject : : activate ( ) ;
}
void CMainMenu : : onScreenResize ( )
{
2025-02-10 21:49:23 +00:00
pos . w = ENGINE - > screenDimensions ( ) . x ;
pos . h = ENGINE - > screenDimensions ( ) . y ;
2023-05-08 00:59:48 +03:00
menu = nullptr ;
menu = std : : make_shared < CMenuScreen > ( CMainMenuConfig : : get ( ) . getConfig ( ) [ " window " ] ) ;
backgroundAroundMenu - > pos = pos ;
}
2025-02-27 22:18:31 +00:00
void CMainMenu : : makeActiveInterface ( )
2018-01-05 20:21:07 +03:00
{
2025-02-27 22:42:29 +00:00
ENGINE - > windows ( ) . pushWindow ( GAME - > mainmenu ( ) ) ;
2025-02-27 22:18:31 +00:00
ENGINE - > windows ( ) . pushWindow ( menu ) ;
menu - > switchToTab ( menu - > getActiveTab ( ) ) ;
2018-01-05 20:21:07 +03:00
}
2024-01-21 16:48:36 +02:00
void CMainMenu : : openLobby ( ESelectionScreen screenType , bool host , const std : : vector < std : : string > & names , ELoadMode loadMode )
2018-01-05 20:21:07 +03:00
{
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . resetStateForLobby ( screenType = = ESelectionScreen : : newGame ? EStartMode : : NEW_GAME : EStartMode : : LOAD_GAME , screenType , EServerMode : : LOCAL , names ) ;
GAME - > server ( ) . loadMode = loadMode ;
2018-01-05 20:21:07 +03:00
2025-02-10 21:49:23 +00:00
ENGINE - > windows ( ) . createAndPushWindow < CSimpleJoinScreen > ( host ) ;
2018-01-05 20:21:07 +03:00
}
2023-09-20 03:13:54 +02:00
void CMainMenu : : openCampaignLobby ( const std : : string & campaignFileName , std : : string campaignSet )
2018-01-05 20:21:07 +03:00
{
2023-06-25 21:16:03 +03:00
auto ourCampaign = CampaignHandler : : getCampaign ( campaignFileName ) ;
2023-09-20 21:18:13 +02:00
ourCampaign - > campaignSet = campaignSet ;
openCampaignLobby ( ourCampaign ) ;
2018-01-05 20:21:07 +03:00
}
2023-09-20 21:18:13 +02:00
void CMainMenu : : openCampaignLobby ( std : : shared_ptr < CampaignState > campaign )
2018-01-05 20:21:07 +03:00
{
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . resetStateForLobby ( EStartMode : : CAMPAIGN , ESelectionScreen : : campaignList , EServerMode : : LOCAL , { } ) ;
GAME - > server ( ) . campaignStateToSend = campaign ;
2025-02-10 21:49:23 +00:00
ENGINE - > windows ( ) . createAndPushWindow < CSimpleJoinScreen > ( ) ;
2018-01-05 20:21:07 +03:00
}
void CMainMenu : : openCampaignScreen ( std : : string name )
{
2023-12-16 15:04:36 +02:00
auto const & config = CMainMenuConfig : : get ( ) . getCampaigns ( ) ;
if ( ! vstd : : contains ( config . Struct ( ) , name ) )
2018-01-05 20:21:07 +03:00
{
2023-12-16 15:04:36 +02:00
logGlobal - > error ( " Unknown campaign set: %s " , name ) ;
2018-01-05 20:21:07 +03:00
return ;
}
2023-12-16 15:04:36 +02:00
2025-02-10 21:49:23 +00:00
ENGINE - > windows ( ) . createAndPushWindow < CCampaignScreen > ( config , name ) ;
2018-01-05 20:21:07 +03:00
}
2023-08-09 03:54:09 +04:00
void CMainMenu : : startTutorial ( )
{
2023-08-23 15:07:50 +03:00
ResourcePath tutorialMap ( " Maps/Tutorial.tut " , EResType : : MAP ) ;
2023-08-09 03:54:09 +04:00
if ( ! CResourceHandler : : get ( ) - > existsResource ( tutorialMap ) )
{
2025-02-14 16:23:37 +00:00
CInfoWindow : : showInfoDialog ( LIBRARY - > generaltexth - > translate ( " core.genrltxt.742 " ) , std : : vector < std : : shared_ptr < CComponent > > ( ) , PlayerColor ( 1 ) ) ;
2023-08-09 03:54:09 +04:00
return ;
}
auto mapInfo = std : : make_shared < CMapInfo > ( ) ;
mapInfo - > mapInit ( tutorialMap . getName ( ) ) ;
2024-01-21 16:48:36 +02:00
CMainMenu : : openLobby ( ESelectionScreen : : newGame , true , { } , ELoadMode : : NONE ) ;
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . startMapAfterConnection ( mapInfo ) ;
2023-08-09 03:54:09 +04:00
}
2023-09-22 01:39:35 +02:00
void CMainMenu : : openHighScoreScreen ( )
{
2025-02-10 21:49:23 +00:00
ENGINE - > windows ( ) . createAndPushWindow < CHighScoreScreen > ( CHighScoreScreen : : HighScorePage : : SCENARIO ) ;
2023-09-22 01:39:35 +02:00
return ;
}
2018-01-05 20:21:07 +03:00
std : : shared_ptr < CPicture > CMainMenu : : createPicture ( const JsonNode & config )
{
2023-08-23 15:07:50 +03:00
return std : : make_shared < CPicture > ( ImagePath : : fromJson ( config [ " name " ] ) , ( int ) config [ " x " ] . Float ( ) , ( int ) config [ " y " ] . Float ( ) ) ;
2018-01-05 20:21:07 +03:00
}
CMultiMode : : CMultiMode ( ESelectionScreen ScreenType )
: screenType ( ScreenType )
{
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2018-01-05 20:21:07 +03:00
2023-08-23 15:07:50 +03:00
background = std : : make_shared < CPicture > ( ImagePath : : builtin ( " MUPOPUP.bmp " ) ) ;
2022-12-12 00:04:46 +02:00
pos = background - > center ( ) ; //center, window has size of bg graphic
2025-01-07 19:30:26 +01:00
const auto & multiplayerConfig = CMainMenuConfig : : get ( ) . getConfig ( ) [ " multiplayer " ] ;
if ( multiplayerConfig . isVector ( ) & & ! multiplayerConfig . Vector ( ) . empty ( ) )
picture = std : : make_shared < CPicture > ( ImagePath : : fromJson ( * RandomGeneratorUtil : : nextItem ( multiplayerConfig . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) , 16 , 77 ) ;
textTitle = std : : make_shared < CTextBox > ( " " , Rect ( 7 , 18 , 440 , 50 ) , 0 , FONT_BIG , ETextAlignment : : CENTER , Colors : : WHITE ) ;
2025-02-14 16:23:37 +00:00
textTitle - > setText ( LIBRARY - > generaltexth - > zelp [ 263 ] . second ) ;
2022-12-11 23:43:43 +02:00
2022-11-29 17:07:21 +02:00
statusBar = CGStatusBar : : create ( std : : make_shared < CPicture > ( background - > getSurface ( ) , Rect ( 7 , 465 , 440 , 18 ) , 7 , 465 ) ) ;
playerName = std : : make_shared < CTextInput > ( Rect ( 19 , 436 , 334 , 16 ) , background - > getSurface ( ) ) ;
2024-06-30 19:51:11 +03:00
playerName - > setText ( getPlayersNames ( ) [ 0 ] ) ;
2024-05-12 14:17:49 +00:00
playerName - > setCallback ( std : : bind ( & CMultiMode : : onNameChange , this , _1 ) ) ;
2018-01-05 20:21:07 +03:00
2025-02-14 16:23:37 +00:00
buttonHotseat = std : : make_shared < CButton > ( Point ( 373 , 78 + 57 * 0 ) , AnimationPath : : builtin ( " MUBHOT.DEF " ) , LIBRARY - > generaltexth - > zelp [ 266 ] , std : : bind ( & CMultiMode : : hostTCP , this , EShortcut : : MAIN_MENU_HOTSEAT ) , EShortcut : : MAIN_MENU_HOTSEAT ) ;
buttonLobby = std : : make_shared < CButton > ( Point ( 373 , 78 + 57 * 1 ) , AnimationPath : : builtin ( " MUBONL.DEF " ) , LIBRARY - > generaltexth - > zelp [ 265 ] , std : : bind ( & CMultiMode : : openLobby , this ) , EShortcut : : MAIN_MENU_LOBBY ) ;
2024-01-10 15:31:11 +02:00
2025-02-14 16:23:37 +00:00
buttonHost = std : : make_shared < CButton > ( Point ( 373 , 78 + 57 * 3 ) , AnimationPath : : builtin ( " MUBHOST.DEF " ) , CButton : : tooltip ( LIBRARY - > generaltexth - > translate ( " vcmi.mainMenu.hostTCP " ) , " " ) , std : : bind ( & CMultiMode : : hostTCP , this , EShortcut : : MAIN_MENU_HOST_GAME ) , EShortcut : : MAIN_MENU_HOST_GAME ) ;
buttonJoin = std : : make_shared < CButton > ( Point ( 373 , 78 + 57 * 4 ) , AnimationPath : : builtin ( " MUBJOIN.DEF " ) , CButton : : tooltip ( LIBRARY - > generaltexth - > translate ( " vcmi.mainMenu.joinTCP " ) , " " ) , std : : bind ( & CMultiMode : : joinTCP , this , EShortcut : : MAIN_MENU_JOIN_GAME ) , EShortcut : : MAIN_MENU_JOIN_GAME ) ;
2023-11-11 16:43:58 +02:00
2025-03-01 10:25:33 +00:00
buttonCancel = std : : make_shared < CButton > ( Point ( 373 , 424 ) , AnimationPath : : builtin ( " MUBCANC.DEF " ) , LIBRARY - > generaltexth - > zelp [ 288 ] , [ this ] ( ) { close ( ) ; } , EShortcut : : GLOBAL_CANCEL ) ;
2018-01-05 20:21:07 +03:00
}
2023-11-11 16:43:58 +02:00
void CMultiMode : : openLobby ( )
{
close ( ) ;
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . getGlobalLobby ( ) . activateInterface ( ) ;
2023-11-11 16:43:58 +02:00
}
2025-01-07 19:30:26 +01:00
void CMultiMode : : hostTCP ( EShortcut shortcut )
2018-01-05 20:21:07 +03:00
{
2018-07-25 01:36:48 +03:00
auto savedScreenType = screenType ;
close ( ) ;
2025-02-10 21:49:23 +00:00
ENGINE - > windows ( ) . createAndPushWindow < CMultiPlayers > ( getPlayersNames ( ) , savedScreenType , true , ELoadMode : : MULTI , shortcut ) ;
2018-01-05 20:21:07 +03:00
}
2025-01-07 19:30:26 +01:00
void CMultiMode : : joinTCP ( EShortcut shortcut )
2018-01-05 20:21:07 +03:00
{
2018-07-25 01:36:48 +03:00
auto savedScreenType = screenType ;
close ( ) ;
2025-02-10 21:49:23 +00:00
ENGINE - > windows ( ) . createAndPushWindow < CMultiPlayers > ( getPlayersNames ( ) , savedScreenType , false , ELoadMode : : MULTI , shortcut ) ;
2023-05-28 16:57:24 +02:00
}
2024-08-12 18:26:30 +00:00
std : : vector < std : : string > CMultiMode : : getPlayersNames ( )
2023-05-28 16:57:24 +02:00
{
2024-06-30 19:51:11 +03:00
std : : vector < std : : string > playerNames ;
std : : string playerNameStr = settings [ " general " ] [ " playerName " ] . String ( ) ;
if ( playerNameStr = = " Player " )
2025-02-14 16:23:37 +00:00
playerNameStr = LIBRARY - > generaltexth - > translate ( " core.genrltxt.434 " ) ;
2024-06-30 19:51:11 +03:00
playerNames . push_back ( playerNameStr ) ;
2024-07-20 12:16:13 +03:00
for ( const auto & playerName : settings [ " general " ] [ " multiPlayerNames " ] . Vector ( ) )
2024-06-30 19:51:11 +03:00
{
2024-07-20 12:16:13 +03:00
const std : : string & nameStr = playerName . String ( ) ;
2024-06-30 19:51:11 +03:00
if ( ! nameStr . empty ( ) )
{
playerNames . push_back ( nameStr ) ;
}
}
return playerNames ;
2018-01-05 20:21:07 +03:00
}
void CMultiMode : : onNameChange ( std : : string newText )
{
Settings name = settings . write [ " general " ] [ " playerName " ] ;
name - > String ( ) = newText ;
}
2025-01-07 19:30:26 +01:00
CMultiPlayers : : CMultiPlayers ( const std : : vector < std : : string > & playerNames , ESelectionScreen ScreenType , bool Host , ELoadMode LoadMode , EShortcut shortcut )
2018-01-05 20:21:07 +03:00
: loadMode ( LoadMode ) , screenType ( ScreenType ) , host ( Host )
{
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2023-08-23 15:07:50 +03:00
background = std : : make_shared < CPicture > ( ImagePath : : builtin ( " MUHOTSEA.bmp " ) ) ;
2018-01-05 20:21:07 +03:00
pos = background - > center ( ) ; //center, window has size of bg graphic
2025-01-07 19:30:26 +01:00
std : : string text ;
switch ( shortcut )
{
case EShortcut : : MAIN_MENU_HOTSEAT :
2025-02-14 16:23:37 +00:00
text = LIBRARY - > generaltexth - > allTexts [ 446 ] ;
2025-01-07 19:30:26 +01:00
boost : : replace_all ( text , " \t " , " \n " ) ;
break ;
case EShortcut : : MAIN_MENU_HOST_GAME :
2025-02-14 16:23:37 +00:00
text = LIBRARY - > generaltexth - > translate ( " vcmi.mainMenu.hostTCP " ) ;
2025-01-07 19:30:26 +01:00
break ;
case EShortcut : : MAIN_MENU_JOIN_GAME :
2025-02-14 16:23:37 +00:00
text = LIBRARY - > generaltexth - > translate ( " vcmi.mainMenu.joinTCP " ) ;
2025-01-07 19:30:26 +01:00
break ;
}
textTitle = std : : make_shared < CTextBox > ( text , Rect ( 25 , 10 , 315 , 60 ) , 0 , FONT_BIG , ETextAlignment : : CENTER , Colors : : WHITE ) ;
2018-01-05 20:21:07 +03:00
for ( int i = 0 ; i < inputNames . size ( ) ; i + + )
{
2022-11-29 17:07:21 +02:00
inputNames [ i ] = std : : make_shared < CTextInput > ( Rect ( 60 , 85 + i * 30 , 280 , 16 ) , background - > getSurface ( ) ) ;
2024-05-12 14:17:49 +00:00
inputNames [ i ] - > setCallback ( std : : bind ( & CMultiPlayers : : onChange , this , _1 ) ) ;
2018-01-05 20:21:07 +03:00
}
2025-02-14 16:23:37 +00:00
buttonOk = std : : make_shared < CButton > ( Point ( 95 , 338 ) , AnimationPath : : builtin ( " MUBCHCK.DEF " ) , LIBRARY - > generaltexth - > zelp [ 560 ] , std : : bind ( & CMultiPlayers : : enterSelectionScreen , this ) , EShortcut : : GLOBAL_ACCEPT ) ;
2025-03-01 10:25:33 +00:00
buttonCancel = std : : make_shared < CButton > ( Point ( 205 , 338 ) , AnimationPath : : builtin ( " MUBCANC.DEF " ) , LIBRARY - > generaltexth - > zelp [ 561 ] , [ this ] ( ) { close ( ) ; } , EShortcut : : GLOBAL_CANCEL ) ;
2022-11-29 17:07:21 +02:00
statusBar = CGStatusBar : : create ( std : : make_shared < CPicture > ( background - > getSurface ( ) , Rect ( 7 , 381 , 348 , 18 ) , 7 , 381 ) ) ;
2018-01-05 20:21:07 +03:00
2024-06-30 19:51:11 +03:00
for ( int i = 0 ; i < playerNames . size ( ) ; i + + )
{
inputNames [ i ] - > setText ( playerNames [ i ] ) ;
}
2024-05-12 14:17:49 +00:00
# ifndef VCMI_MOBILE
2018-01-05 20:21:07 +03:00
inputNames [ 0 ] - > giveFocus ( ) ;
2021-03-16 19:40:56 +03:00
# endif
2018-01-05 20:21:07 +03:00
}
void CMultiPlayers : : onChange ( std : : string newText )
{
}
void CMultiPlayers : : enterSelectionScreen ( )
{
2024-06-30 19:51:11 +03:00
std : : vector < std : : string > playerNames ;
for ( auto playerName : inputNames )
2018-01-05 20:21:07 +03:00
{
2024-06-30 19:51:11 +03:00
if ( playerName - > getText ( ) . length ( ) )
playerNames . push_back ( playerName - > getText ( ) ) ;
2018-01-05 20:21:07 +03:00
}
2024-06-30 19:51:11 +03:00
Settings playerName = settings . write [ " general " ] [ " playerName " ] ;
Settings multiPlayerNames = settings . write [ " general " ] [ " multiPlayerNames " ] ;
multiPlayerNames - > Vector ( ) . clear ( ) ;
2024-07-20 12:16:13 +03:00
if ( ! playerNames . empty ( ) )
2024-06-30 19:51:11 +03:00
{
playerName - > String ( ) = playerNames . front ( ) ;
2024-07-20 12:16:13 +03:00
for ( auto playerNameIt = playerNames . begin ( ) + 1 ; playerNameIt ! = playerNames . end ( ) ; playerNameIt + + )
2024-06-30 19:51:11 +03:00
{
multiPlayerNames - > Vector ( ) . push_back ( JsonNode ( * playerNameIt ) ) ;
}
}
else
{
// Without the check the saving crashes directly.
// When empty reset the player's name. This would translate to it being
// the default for the next run. But enables deleting players, by just
// deleting the names, otherwise some UI element should have been added.
playerName - > clear ( ) ;
}
2018-01-05 20:21:07 +03:00
2024-06-30 19:51:11 +03:00
CMainMenu : : openLobby ( screenType , host , playerNames , loadMode ) ;
2018-01-05 20:21:07 +03:00
}
CSimpleJoinScreen : : CSimpleJoinScreen ( bool host )
{
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2023-08-23 15:07:50 +03:00
background = std : : make_shared < CPicture > ( ImagePath : : builtin ( " MUDIALOG.bmp " ) ) ; // address background
2018-01-05 20:21:07 +03:00
pos = background - > center ( ) ; //center, window has size of bg graphic (x,y = 396,278 w=232 h=212)
2025-01-07 19:30:26 +01:00
textTitle = std : : make_shared < CTextBox > ( " " , Rect ( 20 , 10 , 205 , 50 ) , 0 , FONT_BIG , ETextAlignment : : CENTER , Colors : : WHITE ) ;
2022-11-29 17:07:21 +02:00
inputAddress = std : : make_shared < CTextInput > ( Rect ( 25 , 68 , 175 , 16 ) , background - > getSurface ( ) ) ;
inputPort = std : : make_shared < CTextInput > ( Rect ( 25 , 115 , 175 , 16 ) , background - > getSurface ( ) ) ;
2025-02-14 16:23:37 +00:00
buttonOk = std : : make_shared < CButton > ( Point ( 26 , 142 ) , AnimationPath : : builtin ( " MUBCHCK.DEF " ) , LIBRARY - > generaltexth - > zelp [ 560 ] , std : : bind ( & CSimpleJoinScreen : : connectToServer , this ) , EShortcut : : GLOBAL_ACCEPT ) ;
2018-01-05 20:21:07 +03:00
if ( host & & ! settings [ " session " ] [ " donotstartserver " ] . Bool ( ) )
{
2025-02-14 16:23:37 +00:00
textTitle - > setText ( LIBRARY - > generaltexth - > translate ( " vcmi.mainMenu.serverConnecting " ) ) ;
2023-11-26 18:39:51 +01:00
buttonOk - > block ( true ) ;
2023-11-18 16:34:18 +02:00
startConnection ( ) ;
2018-01-05 20:21:07 +03:00
}
else
{
2025-02-14 16:23:37 +00:00
textTitle - > setText ( LIBRARY - > generaltexth - > translate ( " vcmi.mainMenu.serverAddressEnter " ) ) ;
2024-05-12 14:17:49 +00:00
inputAddress - > setCallback ( std : : bind ( & CSimpleJoinScreen : : onChange , this , _1 ) ) ;
inputPort - > setCallback ( std : : bind ( & CSimpleJoinScreen : : onChange , this , _1 ) ) ;
inputPort - > setFilterNumber ( 0 , 65535 ) ;
2018-01-05 20:21:07 +03:00
inputAddress - > giveFocus ( ) ;
}
2025-02-11 15:23:33 +00:00
inputAddress - > setText ( host ? GAME - > server ( ) . getLocalHostname ( ) : GAME - > server ( ) . getRemoteHostname ( ) ) ;
inputPort - > setText ( std : : to_string ( host ? GAME - > server ( ) . getLocalPort ( ) : GAME - > server ( ) . getRemotePort ( ) ) ) ;
2024-05-12 14:17:49 +00:00
buttonOk - > block ( inputAddress - > getText ( ) . empty ( ) | | inputPort - > getText ( ) . empty ( ) ) ;
2018-01-05 20:21:07 +03:00
2025-02-14 16:23:37 +00:00
buttonCancel = std : : make_shared < CButton > ( Point ( 142 , 142 ) , AnimationPath : : builtin ( " MUBCANC.DEF " ) , LIBRARY - > generaltexth - > zelp [ 561 ] , std : : bind ( & CSimpleJoinScreen : : leaveScreen , this ) , EShortcut : : GLOBAL_CANCEL ) ;
2022-11-29 17:07:21 +02:00
statusBar = CGStatusBar : : create ( std : : make_shared < CPicture > ( background - > getSurface ( ) , Rect ( 7 , 186 , 218 , 18 ) , 7 , 186 ) ) ;
2018-01-05 20:21:07 +03:00
}
void CSimpleJoinScreen : : connectToServer ( )
{
2025-02-14 16:23:37 +00:00
textTitle - > setText ( LIBRARY - > generaltexth - > translate ( " vcmi.mainMenu.serverConnecting " ) ) ;
2018-01-05 20:21:07 +03:00
buttonOk - > block ( true ) ;
2025-02-10 21:49:23 +00:00
ENGINE - > input ( ) . stopTextInput ( ) ;
2018-01-05 20:21:07 +03:00
2023-11-18 16:34:18 +02:00
startConnection ( inputAddress - > getText ( ) , boost : : lexical_cast < ui16 > ( inputPort - > getText ( ) ) ) ;
2018-01-05 20:21:07 +03:00
}
void CSimpleJoinScreen : : leaveScreen ( )
{
2025-02-14 16:23:37 +00:00
textTitle - > setText ( LIBRARY - > generaltexth - > translate ( " vcmi.mainMenu.serverClosing " ) ) ;
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . setState ( EClientState : : CONNECTION_CANCELLED ) ;
2018-01-05 20:21:07 +03:00
}
void CSimpleJoinScreen : : onChange ( const std : : string & newText )
{
2022-12-19 22:04:50 +02:00
buttonOk - > block ( inputAddress - > getText ( ) . empty ( ) | | inputPort - > getText ( ) . empty ( ) ) ;
2018-01-05 20:21:07 +03:00
}
2023-11-18 16:34:18 +02:00
void CSimpleJoinScreen : : startConnection ( const std : : string & addr , ui16 port )
2023-02-26 12:19:24 +03:00
{
2023-11-18 16:34:18 +02:00
if ( addr . empty ( ) )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . startLocalServerAndConnect ( false ) ;
2023-11-18 16:34:18 +02:00
else
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . connectToServer ( addr , port ) ;
2018-01-05 20:21:07 +03:00
}
2023-08-21 05:06:58 +04:00
CLoadingScreen : : CLoadingScreen ( )
2024-08-31 16:03:42 +02:00
: CLoadingScreen ( getBackground ( ) )
{
}
CLoadingScreen : : CLoadingScreen ( ImagePath background )
: CWindowObject ( BORDERED , background )
2018-01-05 20:21:07 +03:00
{
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2025-01-08 00:16:55 +01:00
2023-08-22 16:00:14 +04:00
addUsedEvents ( TIME ) ;
2025-01-08 00:16:55 +01:00
2025-02-10 22:08:50 +00:00
ENGINE - > music ( ) . stopMusic ( 5000 ) ;
2025-01-08 00:16:55 +01:00
const auto & conf = CMainMenuConfig : : get ( ) . getConfig ( ) [ " loading " ] ;
2025-01-31 14:20:10 +01:00
const auto & backgroundConfig = conf [ " background " ] ;
2025-03-07 17:16:17 +01:00
if ( ! backgroundConfig . Vector ( ) . empty ( ) )
backimg = std : : make_shared < CPicture > ( ImagePath : : fromJson ( * RandomGeneratorUtil : : nextItem ( backgroundConfig . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) ) ;
2025-01-08 00:16:55 +01:00
2025-03-07 17:16:17 +01:00
for ( const JsonNode & node : conf [ " images " ] . Vector ( ) )
2025-03-03 17:38:54 +01:00
{
2025-03-07 17:16:17 +01:00
auto image = std : : make_shared < CPicture > ( ImagePath : : fromJson ( * RandomGeneratorUtil : : nextItem ( node [ " name " ] . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) , Point ( node [ " x " ] . Integer ( ) , node [ " y " ] . Integer ( ) ) ) ;
images . push_back ( image ) ;
2025-01-31 14:20:10 +01:00
}
2025-01-08 00:16:55 +01:00
2025-01-31 14:20:10 +01:00
const auto & loadframeConfig = conf [ " loadframe " ] ;
2025-03-03 17:38:54 +01:00
if ( loadframeConfig . isStruct ( ) )
{
2025-03-07 17:16:17 +01:00
loadFrame = std : : make_shared < CPicture > (
2025-01-31 14:20:10 +01:00
ImagePath : : fromJson ( * RandomGeneratorUtil : : nextItem ( loadframeConfig [ " name " ] . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) ,
loadframeConfig [ " x " ] . Integer ( ) ,
loadframeConfig [ " y " ] . Integer ( )
) ;
}
const auto & loadbarConfig = conf [ " loadbar " ] ;
2025-03-03 17:38:54 +01:00
if ( loadbarConfig . isStruct ( ) )
{
2025-01-31 14:20:10 +01:00
AnimationPath loadbarPath = AnimationPath : : fromJson ( * RandomGeneratorUtil : : nextItem ( loadbarConfig [ " name " ] . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) ;
const int posx = loadbarConfig [ " x " ] . Integer ( ) ;
const int posy = loadbarConfig [ " y " ] . Integer ( ) ;
const int blockSize = loadbarConfig [ " size " ] . Integer ( ) ;
const int blocksAmount = loadbarConfig [ " amount " ] . Integer ( ) ;
for ( int i = 0 ; i < blocksAmount ; + + i )
2023-08-22 00:32:26 +04:00
{
2025-01-31 14:20:10 +01:00
progressBlocks . push_back ( std : : make_shared < CAnimImage > ( loadbarPath , i , 0 , posx + i * blockSize , posy ) ) ;
2023-08-22 00:32:26 +04:00
progressBlocks . back ( ) - > deactivate ( ) ;
progressBlocks . back ( ) - > visible = false ;
}
2023-08-21 18:56:01 +04:00
}
2018-01-05 20:21:07 +03:00
}
CLoadingScreen : : ~ CLoadingScreen ( )
{
}
2023-08-22 16:00:14 +04:00
void CLoadingScreen : : tick ( uint32_t msPassed )
2018-01-05 20:21:07 +03:00
{
2023-08-21 18:56:01 +04:00
if ( ! progressBlocks . empty ( ) )
{
2023-08-21 19:09:56 +04:00
int status = float ( get ( ) ) / 255.f * progressBlocks . size ( ) ;
2023-08-21 18:56:01 +04:00
for ( int i = 0 ; i < status ; + + i )
{
progressBlocks . at ( i ) - > activate ( ) ;
progressBlocks . at ( i ) - > visible = true ;
}
}
2018-01-05 20:21:07 +03:00
}
2023-08-23 15:07:50 +03:00
ImagePath CLoadingScreen : : getBackground ( )
2018-01-05 20:21:07 +03:00
{
2023-08-23 15:07:50 +03:00
ImagePath fname = ImagePath : : builtin ( " loadbar " ) ;
2023-08-22 00:32:26 +04:00
const auto & conf = CMainMenuConfig : : get ( ) . getConfig ( ) [ " loading " ] ;
2018-01-05 20:21:07 +03:00
2023-08-22 00:32:26 +04:00
if ( conf . isStruct ( ) )
2018-01-05 20:21:07 +03:00
{
2023-08-22 00:32:26 +04:00
if ( conf [ " background " ] . isVector ( ) )
2023-08-23 15:07:50 +03:00
return ImagePath : : fromJson ( * RandomGeneratorUtil : : nextItem ( conf [ " background " ] . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) ;
2023-08-22 00:32:26 +04:00
if ( conf [ " background " ] . isString ( ) )
2023-08-23 15:07:50 +03:00
return ImagePath : : fromJson ( conf [ " background " ] ) ;
2023-08-22 00:32:26 +04:00
return fname ;
2018-01-05 20:21:07 +03:00
}
2023-08-22 00:32:26 +04:00
2023-08-23 01:20:29 +04:00
if ( conf . isVector ( ) & & ! conf . Vector ( ) . empty ( ) )
2023-08-23 15:07:50 +03:00
return ImagePath : : fromJson ( * RandomGeneratorUtil : : nextItem ( conf . Vector ( ) , CRandomGenerator : : getDefault ( ) ) ) ;
2023-08-22 00:32:26 +04:00
return fname ;
2018-01-05 20:21:07 +03:00
}