2018-01-05 19:21:07 +02: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"
# include "../lobby/CBonusSelection.h"
# include "../lobby/CSelectionBase.h"
# include "../lobby/CLobbyScreen.h"
2023-01-05 19:34:37 +02:00
# include "../gui/CursorHandler.h"
2018-01-05 19:21:07 +02:00
# include "../windows/GUIClasses.h"
# include "../gui/CGuiHandler.h"
2023-04-27 19:21:06 +02:00
# include "../gui/ShortcutHandler.h"
# include "../gui/Shortcut.h"
2023-05-16 14:10:26 +02:00
# include "../gui/WindowHandler.h"
2018-01-05 19:21:07 +02:00
# include "../widgets/CComponent.h"
# include "../widgets/Buttons.h"
# include "../widgets/MiscWidgets.h"
# include "../widgets/ObjectLists.h"
# include "../widgets/TextControls.h"
# include "../windows/InfoWindows.h"
# include "../CServerHandler.h"
2023-02-02 21:15:13 +02:00
# include "../CGameInfo.h"
# include "../CMusicHandler.h"
# include "../CVideoHandler.h"
# 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
# include "../../CCallback.h"
# include "../../lib/CGeneralTextHandler.h"
# include "../../lib/JsonNode.h"
# include "../../lib/serializer/Connection.h"
# include "../../lib/serializer/CTypeList.h"
# include "../../lib/filesystem/Filesystem.h"
# include "../../lib/filesystem/CCompressedStream.h"
# include "../../lib/VCMIDirs.h"
# include "../../lib/mapping/CMap.h"
2018-01-05 19:21:07 +02:00
# include "../../lib/CStopWatch.h"
# include "../../lib/NetPacksLobby.h"
# include "../../lib/CThreadHelper.h"
# include "../../lib/CConfigHandler.h"
# include "../../lib/GameConstants.h"
# include "../../lib/CRandomGenerator.h"
# include "../../lib/CondSh.h"
# include "../../lib/mapping/CCampaignHandler.h"
2023-02-26 11:19:24 +02:00
# if defined(SINGLE_PROCESS_APP) && defined(VCMI_ANDROID)
# include "../../server/CVCMIServer.h"
# include <SDL.h>
# endif
2018-01-05 19:21:07 +02:00
namespace fs = boost : : filesystem ;
2018-07-25 00:36:48 +02:00
std : : shared_ptr < CMainMenu > CMM ;
2018-01-05 19:21:07 +02:00
ISelectionScreenInfo * SEL ;
static void do_quit ( )
{
2023-02-02 20:16:41 +02:00
GH . pushUserEvent ( EUserEvent : : FORCE_QUIT ) ;
2018-01-05 19:21:07 +02:00
}
CMenuScreen : : CMenuScreen ( const JsonNode & configNode )
: CWindowObject ( BORDERED ) , config ( configNode )
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE ;
background = std : : make_shared < CPicture > ( config [ " background " ] . String ( ) ) ;
if ( config [ " scalable " ] . Bool ( ) )
2023-02-03 18:23:53 +02:00
background - > scaleTo ( GH . screenDimensions ( ) ) ;
2018-01-05 19:21:07 +02:00
pos = background - > center ( ) ;
for ( const JsonNode & node : config [ " items " ] . Vector ( ) )
menuNameToEntry . push_back ( node [ " name " ] . String ( ) ) ;
for ( const JsonNode & node : config [ " images " ] . Vector ( ) )
images . push_back ( CMainMenu : : createPicture ( node ) ) ;
//Hardcoded entry
menuNameToEntry . push_back ( " credits " ) ;
2018-04-07 13:34:11 +02:00
tabs = std : : make_shared < CTabbedInt > ( std : : bind ( & CMenuScreen : : createTab , this , _1 ) ) ;
2018-01-05 19:21:07 +02:00
tabs - > type | = REDRAW_PARENT ;
}
2018-04-07 13:34:11 +02:00
std : : shared_ptr < CIntObject > CMenuScreen : : createTab ( size_t index )
2018-01-05 19:21:07 +02:00
{
if ( config [ " items " ] . Vector ( ) . size ( ) = = index )
2018-04-07 13:42:11 +02:00
return std : : make_shared < CreditsScreen > ( this - > pos ) ;
2018-04-07 13:34:11 +02:00
else
return std : : make_shared < CMenuEntry > ( this , config [ " items " ] . Vector ( ) [ index ] ) ;
2018-01-05 19:21:07 +02:00
}
void CMenuScreen : : show ( SDL_Surface * to )
{
if ( ! config [ " video " ] . isNull ( ) )
2020-10-01 10:38:06 +02:00
CCS - > videoh - > update ( ( int ) config [ " video " ] [ " x " ] . Float ( ) + pos . x , ( int ) config [ " video " ] [ " y " ] . Float ( ) + pos . y , to , true , false ) ;
2018-01-05 19:21:07 +02:00
CIntObject : : show ( to ) ;
}
void CMenuScreen : : activate ( )
{
2022-11-13 14:24:15 +02:00
CCS - > musich - > playMusic ( " Music/MainMenu " , true , true ) ;
2018-01-05 19:21:07 +02:00
if ( ! config [ " video " ] . isNull ( ) )
CCS - > videoh - > open ( config [ " video " ] [ " name " ] . String ( ) ) ;
CIntObject : : activate ( ) ;
}
void CMenuScreen : : deactivate ( )
{
if ( ! config [ " video " ] . isNull ( ) )
CCS - > videoh - > close ( ) ;
CIntObject : : deactivate ( ) ;
}
void CMenuScreen : : switchToTab ( size_t index )
{
tabs - > setActive ( index ) ;
}
2018-04-07 13:42:11 +02:00
void CMenuScreen : : switchToTab ( std : : string name )
{
switchToTab ( vstd : : find_pos ( menuNameToEntry , name ) ) ;
}
2021-01-17 18:16:34 +02:00
size_t CMenuScreen : : getActiveTab ( ) const
{
return tabs - > getActive ( ) ;
}
2018-01-05 19:21:07 +02:00
//funciton for std::string -> std::function conversion for main menu
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 13:42:11 +02:00
return std : : bind ( ( void ( CMenuScreen : : * ) ( size_t ) ) & CMenuScreen : : switchToTab , menu , index2 ) ;
2018-01-05 19:21:07 +02:00
break ;
}
case 1 : //open campaign selection window
{
return std : : bind ( & CMainMenu : : openCampaignScreen , CMM , commands . front ( ) ) ;
break ;
}
case 2 : //start
{
switch ( std : : find ( gameType . begin ( ) , gameType . end ( ) , commands . front ( ) ) - gameType . begin ( ) )
{
case 0 :
return std : : bind ( CMainMenu : : openLobby , ESelectionScreen : : newGame , true , nullptr , ELoadMode : : NONE ) ;
case 1 :
2023-05-16 14:10:26 +02:00
return [ ] ( ) { GH . windows ( ) . pushIntT < CMultiMode > ( ESelectionScreen : : newGame ) ; } ;
2018-01-05 19:21:07 +02:00
case 2 :
return std : : bind ( CMainMenu : : openLobby , ESelectionScreen : : campaignList , true , nullptr , ELoadMode : : NONE ) ;
case 3 :
2018-04-07 13:34:11 +02:00
return std : : bind ( CInfoWindow : : showInfoDialog , " Sorry, tutorial is not implemented yet \n " , std : : vector < std : : shared_ptr < CComponent > > ( ) , PlayerColor ( 1 ) ) ;
2018-01-05 19:21:07 +02:00
}
break ;
}
case 3 : //load
{
switch ( std : : find ( gameType . begin ( ) , gameType . end ( ) , commands . front ( ) ) - gameType . begin ( ) )
{
case 0 :
return std : : bind ( CMainMenu : : openLobby , ESelectionScreen : : loadGame , true , nullptr , ELoadMode : : SINGLE ) ;
case 1 :
2023-05-16 14:10:26 +02:00
return [ ] ( ) { GH . windows ( ) . pushIntT < CMultiMode > ( ESelectionScreen : : loadGame ) ; } ;
2018-01-05 19:21:07 +02:00
case 2 :
return std : : bind ( CMainMenu : : openLobby , ESelectionScreen : : loadGame , true , nullptr , ELoadMode : : CAMPAIGN ) ;
case 3 :
2018-04-07 13:34:11 +02:00
return std : : bind ( CInfoWindow : : showInfoDialog , " Sorry, tutorial is not implemented yet \n " , std : : vector < std : : shared_ptr < CComponent > > ( ) , PlayerColor ( 1 ) ) ;
2018-01-05 19:21:07 +02:00
}
}
break ;
case 4 : //exit
{
2023-01-01 20:54:05 +02:00
return std : : bind ( CInfoWindow : : showYesNoDialog , CGI - > generaltexth - > allTexts [ 69 ] , std : : vector < std : : shared_ptr < CComponent > > ( ) , do_quit , 0 , PlayerColor ( 1 ) ) ;
2018-01-05 19:21:07 +02:00
}
break ;
case 5 : //highscores
{
2018-04-07 13:34:11 +02:00
return std : : bind ( CInfoWindow : : showInfoDialog , " Sorry, high scores menu is not implemented yet \n " , std : : vector < std : : shared_ptr < CComponent > > ( ) , PlayerColor ( 1 ) ) ;
2018-01-05 19:21:07 +02: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 )
2020-10-01 10:38:06 +02:00
help = CGI - > generaltexth - > zelp [ ( size_t ) button [ " help " ] . Float ( ) ] ;
2018-01-05 19:21:07 +02:00
2020-10-01 10:38:06 +02:00
int posx = static_cast < int > ( button [ " x " ] . Float ( ) ) ;
2018-01-05 19:21:07 +02:00
if ( posx < 0 )
posx = pos . w + posx ;
2020-10-01 10:38:06 +02:00
int posy = static_cast < int > ( button [ " y " ] . Float ( ) ) ;
2018-01-05 19:21:07 +02:00
if ( posy < 0 )
posy = pos . h + posy ;
2023-04-28 13:22:03 +02:00
EShortcut shortcut = GH . shortcutsHandler ( ) . findShortcut ( button [ " shortcut " ] . String ( ) ) ;
2023-04-27 19:21:06 +02:00
auto result = std : : make_shared < CButton > ( Point ( posx , posy ) , button [ " name " ] . String ( ) , 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 ) ) ;
return result ;
2018-01-05 19:21:07 +02:00
}
CMenuEntry : : CMenuEntry ( CMenuScreen * parent , const JsonNode & config )
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE ;
type | = REDRAW_PARENT ;
pos = parent - > pos ;
for ( const JsonNode & node : config [ " images " ] . Vector ( ) )
images . push_back ( CMainMenu : : createPicture ( node ) ) ;
for ( const JsonNode & node : config [ " buttons " ] . Vector ( ) )
{
buttons . push_back ( createButton ( parent , node ) ) ;
buttons . back ( ) - > hoverable = true ;
buttons . back ( ) - > type | = REDRAW_PARENT ;
}
}
CMainMenuConfig : : CMainMenuConfig ( )
: campaignSets ( JsonNode ( ResourceID ( " config/campaignSets.json " ) ) ) , config ( JsonNode ( ResourceID ( " config/mainmenu.json " ) ) )
{
}
CMainMenuConfig & CMainMenuConfig : : get ( )
{
static CMainMenuConfig config ;
return config ;
}
const JsonNode & CMainMenuConfig : : getConfig ( ) const
{
return config ;
}
const JsonNode & CMainMenuConfig : : getCampaigns ( ) const
{
return campaignSets ;
}
CMainMenu : : CMainMenu ( )
{
2023-02-03 18:23:53 +02:00
pos . w = GH . screenDimensions ( ) . x ;
pos . h = GH . screenDimensions ( ) . y ;
2018-01-05 19:21:07 +02:00
GH . defActionsDef = 63 ;
2018-07-25 00:36:48 +02:00
menu = std : : make_shared < CMenuScreen > ( CMainMenuConfig : : get ( ) . getConfig ( ) [ " window " ] ) ;
2018-01-05 19:21:07 +02:00
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE ;
backgroundAroundMenu = std : : make_shared < CFilledTexture > ( " DIBOXBCK " , pos ) ;
}
CMainMenu : : ~ CMainMenu ( )
{
boost : : unique_lock < boost : : recursive_mutex > lock ( * CPlayerInterface : : pim ) ;
if ( GH . curInt = = this )
GH . curInt = nullptr ;
}
2023-05-07 23:59:48 +02:00
void CMainMenu : : activate ( )
{
// check if screen was resized while main menu was inactive - e.g. in gameplay mode
if ( pos . dimensions ( ) ! = GH . screenDimensions ( ) )
onScreenResize ( ) ;
CIntObject : : activate ( ) ;
}
void CMainMenu : : onScreenResize ( )
{
pos . w = GH . screenDimensions ( ) . x ;
pos . h = GH . screenDimensions ( ) . y ;
menu = nullptr ;
menu = std : : make_shared < CMenuScreen > ( CMainMenuConfig : : get ( ) . getConfig ( ) [ " window " ] ) ;
backgroundAroundMenu - > pos = pos ;
}
2018-01-05 19:21:07 +02:00
void CMainMenu : : update ( )
{
2018-07-25 00:36:48 +02:00
if ( CMM ! = this - > shared_from_this ( ) ) //don't update if you are not a main interface
2018-01-05 19:21:07 +02:00
return ;
2023-05-16 15:07:03 +02:00
if ( GH . windows ( ) . count ( ) = = 0 )
2018-01-05 19:21:07 +02:00
{
2023-05-16 14:10:26 +02:00
GH . windows ( ) . pushInt ( CMM ) ;
GH . windows ( ) . pushInt ( menu ) ;
2021-01-17 18:16:34 +02:00
menu - > switchToTab ( menu - > getActiveTab ( ) ) ;
2018-01-05 19:21:07 +02:00
}
// Handles mouse and key input
GH . updateTime ( ) ;
GH . handleEvents ( ) ;
// check for null othervice crash on finishing a campaign
2023-05-16 14:10:26 +02:00
// /FIXME: find out why GH.windows().listInt is empty to begin with
if ( GH . windows ( ) . topInt ( ) )
GH . windows ( ) . topInt ( ) - > show ( screen ) ;
2018-01-05 19:21:07 +02:00
}
void CMainMenu : : openLobby ( ESelectionScreen screenType , bool host , const std : : vector < std : : string > * names , ELoadMode loadMode )
{
CSH - > resetStateForLobby ( screenType = = ESelectionScreen : : newGame ? StartInfo : : NEW_GAME : StartInfo : : LOAD_GAME , names ) ;
CSH - > screenType = screenType ;
CSH - > loadMode = loadMode ;
2023-05-16 14:10:26 +02:00
GH . windows ( ) . pushIntT < CSimpleJoinScreen > ( host ) ;
2018-01-05 19:21:07 +02:00
}
void CMainMenu : : openCampaignLobby ( const std : : string & campaignFileName )
{
auto ourCampaign = std : : make_shared < CCampaignState > ( CCampaignHandler : : getCampaign ( campaignFileName ) ) ;
openCampaignLobby ( ourCampaign ) ;
}
void CMainMenu : : openCampaignLobby ( std : : shared_ptr < CCampaignState > campaign )
{
CSH - > resetStateForLobby ( StartInfo : : CAMPAIGN ) ;
CSH - > screenType = ESelectionScreen : : campaignList ;
CSH - > campaignStateToSend = campaign ;
2023-05-16 14:10:26 +02:00
GH . windows ( ) . pushIntT < CSimpleJoinScreen > ( ) ;
2018-01-05 19:21:07 +02:00
}
void CMainMenu : : openCampaignScreen ( std : : string name )
{
if ( vstd : : contains ( CMainMenuConfig : : get ( ) . getCampaigns ( ) . Struct ( ) , name ) )
{
2023-05-16 14:10:26 +02:00
GH . windows ( ) . pushIntT < CCampaignScreen > ( CMainMenuConfig : : get ( ) . getCampaigns ( ) [ name ] ) ;
2018-01-05 19:21:07 +02:00
return ;
}
logGlobal - > error ( " Unknown campaign set: %s " , name ) ;
}
2018-07-25 00:36:48 +02:00
std : : shared_ptr < CMainMenu > CMainMenu : : create ( )
2018-01-05 19:21:07 +02:00
{
if ( ! CMM )
2018-07-25 00:36:48 +02:00
CMM = std : : shared_ptr < CMainMenu > ( new CMainMenu ( ) ) ;
2018-01-05 19:21:07 +02:00
2019-03-29 23:01:51 +02:00
GH . terminate_cond - > setn ( false ) ;
2018-01-05 19:21:07 +02:00
return CMM ;
}
std : : shared_ptr < CPicture > CMainMenu : : createPicture ( const JsonNode & config )
{
2020-10-01 10:38:06 +02:00
return std : : make_shared < CPicture > ( config [ " name " ] . String ( ) , ( int ) config [ " x " ] . Float ( ) , ( int ) config [ " y " ] . Float ( ) ) ;
2018-01-05 19:21:07 +02:00
}
CMultiMode : : CMultiMode ( ESelectionScreen ScreenType )
: screenType ( ScreenType )
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE ;
2022-12-11 23:43:43 +02:00
background = std : : make_shared < CPicture > ( " MUPOPUP.bmp " ) ;
2022-12-12 00:04:46 +02:00
pos = background - > center ( ) ; //center, window has size of bg graphic
picture = std : : make_shared < CPicture > ( " MUMAP.bmp " , 16 , 77 ) ;
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 ( ) ) ;
2018-01-05 19:21:07 +02:00
playerName - > setText ( settings [ " general " ] [ " playerName " ] . String ( ) ) ;
playerName - > cb + = std : : bind ( & CMultiMode : : onNameChange , this , _1 ) ;
buttonHotseat = std : : make_shared < CButton > ( Point ( 373 , 78 ) , " MUBHOT.DEF " , CGI - > generaltexth - > zelp [ 266 ] , std : : bind ( & CMultiMode : : hostTCP , this ) ) ;
buttonHost = std : : make_shared < CButton > ( Point ( 373 , 78 + 57 * 1 ) , " MUBHOST.DEF " , CButton : : tooltip ( " Host TCP/IP game " , " " ) , std : : bind ( & CMultiMode : : hostTCP , this ) ) ;
buttonJoin = std : : make_shared < CButton > ( Point ( 373 , 78 + 57 * 2 ) , " MUBJOIN.DEF " , CButton : : tooltip ( " Join TCP/IP game " , " " ) , std : : bind ( & CMultiMode : : joinTCP , this ) ) ;
2023-04-27 19:21:06 +02:00
buttonCancel = std : : make_shared < CButton > ( Point ( 373 , 424 ) , " MUBCANC.DEF " , CGI - > generaltexth - > zelp [ 288 ] , [ = ] ( ) { close ( ) ; } , EShortcut : : GLOBAL_CANCEL ) ;
2018-01-05 19:21:07 +02:00
}
void CMultiMode : : hostTCP ( )
{
2018-07-25 00:36:48 +02:00
auto savedScreenType = screenType ;
close ( ) ;
2023-05-16 14:10:26 +02:00
GH . windows ( ) . pushIntT < CMultiPlayers > ( settings [ " general " ] [ " playerName " ] . String ( ) , savedScreenType , true , ELoadMode : : MULTI ) ;
2018-01-05 19:21:07 +02:00
}
void CMultiMode : : joinTCP ( )
{
2018-07-25 00:36:48 +02:00
auto savedScreenType = screenType ;
close ( ) ;
2023-05-16 14:10:26 +02:00
GH . windows ( ) . pushIntT < CMultiPlayers > ( settings [ " general " ] [ " playerName " ] . String ( ) , savedScreenType , false , ELoadMode : : MULTI ) ;
2018-01-05 19:21:07 +02:00
}
void CMultiMode : : onNameChange ( std : : string newText )
{
Settings name = settings . write [ " general " ] [ " playerName " ] ;
name - > String ( ) = newText ;
}
CMultiPlayers : : CMultiPlayers ( const std : : string & firstPlayer , ESelectionScreen ScreenType , bool Host , ELoadMode LoadMode )
: loadMode ( LoadMode ) , screenType ( ScreenType ) , host ( Host )
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE ;
background = std : : make_shared < CPicture > ( " MUHOTSEA.bmp " ) ;
pos = background - > center ( ) ; //center, window has size of bg graphic
std : : string text = CGI - > generaltexth - > allTexts [ 446 ] ;
boost : : replace_all ( text , " \t " , " \n " ) ;
2022-11-26 23:12:20 +02:00
textTitle = std : : make_shared < CTextBox > ( text , Rect ( 25 , 20 , 315 , 50 ) , 0 , FONT_BIG , ETextAlignment : : CENTER , Colors : : WHITE ) ; //HOTSEAT Please enter names
2018-01-05 19:21:07 +02: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 ( ) ) ;
2018-01-05 19:21:07 +02:00
inputNames [ i ] - > cb + = std : : bind ( & CMultiPlayers : : onChange , this , _1 ) ;
}
2023-04-28 13:22:03 +02:00
buttonOk = std : : make_shared < CButton > ( Point ( 95 , 338 ) , " MUBCHCK.DEF " , CGI - > generaltexth - > zelp [ 560 ] , std : : bind ( & CMultiPlayers : : enterSelectionScreen , this ) , EShortcut : : GLOBAL_ACCEPT ) ;
2023-04-27 19:21:06 +02:00
buttonCancel = std : : make_shared < CButton > ( Point ( 205 , 338 ) , " MUBCANC.DEF " , CGI - > generaltexth - > zelp [ 561 ] , [ = ] ( ) { 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 19:21:07 +02:00
inputNames [ 0 ] - > setText ( firstPlayer , true ) ;
2021-03-16 18:40:56 +02:00
# ifndef VCMI_IOS
2018-01-05 19:21:07 +02:00
inputNames [ 0 ] - > giveFocus ( ) ;
2021-03-16 18:40:56 +02:00
# endif
2018-01-05 19:21:07 +02:00
}
void CMultiPlayers : : onChange ( std : : string newText )
{
}
void CMultiPlayers : : enterSelectionScreen ( )
{
std : : vector < std : : string > names ;
for ( auto name : inputNames )
{
2022-12-19 22:04:50 +02:00
if ( name - > getText ( ) . length ( ) )
names . push_back ( name - > getText ( ) ) ;
2018-01-05 19:21:07 +02:00
}
Settings name = settings . write [ " general " ] [ " playerName " ] ;
name - > String ( ) = names [ 0 ] ;
CMainMenu : : openLobby ( screenType , host , & names , loadMode ) ;
}
CSimpleJoinScreen : : CSimpleJoinScreen ( bool host )
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE ;
background = std : : make_shared < CPicture > ( " MUDIALOG.bmp " ) ; // address background
pos = background - > center ( ) ; //center, window has size of bg graphic (x,y = 396,278 w=232 h=212)
2022-11-26 23:12:20 +02:00
textTitle = std : : make_shared < CTextBox > ( " " , Rect ( 20 , 20 , 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 ( ) ) ;
2018-01-05 19:21:07 +02:00
if ( host & & ! settings [ " session " ] [ " donotstartserver " ] . Bool ( ) )
{
textTitle - > setText ( " Connecting... " ) ;
2023-02-26 11:19:24 +02:00
startConnectThread ( ) ;
2018-01-05 19:21:07 +02:00
}
else
{
textTitle - > setText ( " Enter address: " ) ;
inputAddress - > cb + = std : : bind ( & CSimpleJoinScreen : : onChange , this , _1 ) ;
inputPort - > cb + = std : : bind ( & CSimpleJoinScreen : : onChange , this , _1 ) ;
inputPort - > filters + = std : : bind ( & CTextInput : : numberFilter , _1 , _2 , 0 , 65535 ) ;
2023-04-28 13:22:03 +02:00
buttonOk = std : : make_shared < CButton > ( Point ( 26 , 142 ) , " MUBCHCK.DEF " , CGI - > generaltexth - > zelp [ 560 ] , std : : bind ( & CSimpleJoinScreen : : connectToServer , this ) , EShortcut : : GLOBAL_ACCEPT ) ;
2018-01-05 19:21:07 +02:00
inputAddress - > giveFocus ( ) ;
}
2022-11-08 02:44:34 +02:00
inputAddress - > setText ( host ? CServerHandler : : localhostAddress : CSH - > getHostAddress ( ) , true ) ;
2023-03-09 15:36:46 +02:00
inputPort - > setText ( std : : to_string ( CSH - > getHostPort ( ) ) , true ) ;
2018-01-05 19:21:07 +02:00
2023-04-27 19:21:06 +02:00
buttonCancel = std : : make_shared < CButton > ( Point ( 142 , 142 ) , " MUBCANC.DEF " , CGI - > 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 19:21:07 +02:00
}
void CSimpleJoinScreen : : connectToServer ( )
{
textTitle - > setText ( " Connecting... " ) ;
buttonOk - > block ( true ) ;
2023-02-02 16:15:39 +02:00
GH . stopTextInput ( ) ;
2018-01-05 19:21:07 +02:00
2023-02-26 11:19:24 +02:00
startConnectThread ( inputAddress - > getText ( ) , boost : : lexical_cast < ui16 > ( inputPort - > getText ( ) ) ) ;
2018-01-05 19:21:07 +02:00
}
void CSimpleJoinScreen : : leaveScreen ( )
{
if ( CSH - > state = = EClientState : : CONNECTING )
{
textTitle - > setText ( " Closing... " ) ;
CSH - > state = EClientState : : CONNECTION_CANCELLED ;
}
2023-05-16 15:07:03 +02:00
else if ( GH . windows ( ) . topInt ( ) . get ( ) = = this )
2018-01-05 19:21:07 +02:00
{
2018-07-25 00:36:48 +02:00
close ( ) ;
2018-01-05 19:21:07 +02: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 19:21:07 +02:00
}
2023-02-26 11:19:24 +02:00
void CSimpleJoinScreen : : startConnectThread ( const std : : string & addr , ui16 port )
{
# if defined(SINGLE_PROCESS_APP) && defined(VCMI_ANDROID)
// in single process build server must use same JNIEnv as client
// as server runs in a separate thread, it must not attempt to search for Java classes (and they're already cached anyway)
// https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md#threads-and-the-java-vm
CVCMIServer : : reuseClientJNIEnv ( SDL_AndroidGetJNIEnv ( ) ) ;
# endif
boost : : thread ( & CSimpleJoinScreen : : connectThread , this , addr , port ) ;
}
void CSimpleJoinScreen : : connectThread ( const std : : string & addr , ui16 port )
2018-01-05 19:21:07 +02:00
{
setThreadName ( " CSimpleJoinScreen::connectThread " ) ;
if ( ! addr . length ( ) )
CSH - > startLocalServerAndConnect ( ) ;
else
CSH - > justConnectToServer ( addr , port ) ;
2023-05-16 15:07:03 +02:00
if ( GH . windows ( ) . topInt ( ) . get ( ) = = this )
2018-01-05 19:21:07 +02:00
{
2018-07-25 00:36:48 +02:00
close ( ) ;
2018-01-05 19:21:07 +02:00
}
}
CLoadingScreen : : CLoadingScreen ( std : : function < void ( ) > loader )
: CWindowObject ( BORDERED , getBackground ( ) ) , loadingThread ( loader )
{
CCS - > musich - > stopMusic ( 5000 ) ;
}
CLoadingScreen : : ~ CLoadingScreen ( )
{
loadingThread . join ( ) ;
}
void CLoadingScreen : : showAll ( SDL_Surface * to )
{
2023-01-17 22:01:35 +02:00
//FIXME: filling screen with transparency? BLACK intended?
//Rect rect(0, 0, to->w, to->h);
//CSDL_Ext::fillRect(to, rect, Colors::TRANSPARENCY);
2018-01-05 19:21:07 +02:00
CWindowObject : : showAll ( to ) ;
}
std : : string CLoadingScreen : : getBackground ( )
{
const auto & conf = CMainMenuConfig : : get ( ) . getConfig ( ) [ " loading " ] . Vector ( ) ;
if ( conf . empty ( ) )
{
return " loadbar " ;
}
else
{
return RandomGeneratorUtil : : nextItem ( conf , CRandomGenerator : : getDefault ( ) ) - > String ( ) ;
}
}