2018-01-05 20:21:07 +03:00
/*
* CLobbyScreen . 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 "CLobbyScreen.h"
2023-11-09 16:41:00 +02:00
2018-01-05 20:21:07 +03:00
# include "CBonusSelection.h"
2023-11-09 16:41:00 +02:00
# include "TurnOptionsTab.h"
2023-12-28 19:41:01 +01:00
# include "ExtraOptionsTab.h"
2018-01-05 20:21:07 +03:00
# include "OptionsTab.h"
2023-11-09 16:41:00 +02:00
# include "RandomMapTab.h"
# include "SelectionTab.h"
2018-01-05 20:21:07 +03:00
2023-11-09 16:41:00 +02:00
# include "../CServerHandler.h"
2025-02-10 21:49:23 +00:00
# include "../GameEngine.h"
2025-02-11 15:23:33 +00:00
# include "../GameInstance.h"
2023-04-27 20:21:06 +03:00
# include "../gui/Shortcut.h"
2018-01-05 20:21:07 +03:00
# include "../widgets/Buttons.h"
2024-12-27 21:22:45 +01:00
# include "../widgets/GraphicalPrimitiveCanvas.h"
2018-01-05 20:21:07 +03:00
# include "../windows/InfoWindows.h"
2023-07-31 19:50:55 +03:00
# include "../render/Colors.h"
2024-03-26 23:51:42 +02:00
# include "../globalLobby/GlobalLobbyClient.h"
2018-01-05 20:21:07 +03:00
2023-11-13 19:49:41 +02:00
# include "../../lib/CConfigHandler.h"
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"
2018-01-05 20:21:07 +03:00
# include "../../lib/mapping/CMapInfo.h"
2023-11-13 19:49:41 +02:00
# include "../../lib/networkPacks/PacksForLobby.h"
2018-01-05 20:21:07 +03:00
# include "../../lib/rmg/CMapGenOptions.h"
2025-02-14 16:23:37 +00:00
# include "../../lib/GameLibrary.h"
2018-01-05 20:21:07 +03:00
2024-12-27 21:40:09 +01:00
CLobbyScreen : : CLobbyScreen ( ESelectionScreen screenType , bool hideScreen )
2018-01-05 20:21:07 +03:00
: CSelectionBase ( screenType ) , bonusSel ( nullptr )
{
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2018-01-05 20:21:07 +03:00
tabSel = std : : make_shared < SelectionTab > ( screenType ) ;
curTab = tabSel ;
auto initLobby = [ & ] ( )
{
2025-02-11 15:23:33 +00:00
tabSel - > callOnSelect = std : : bind ( & IServerAPI : : setMapInfo , & GAME - > server ( ) , _1 , nullptr ) ;
2018-01-05 20:21:07 +03:00
2025-02-14 16:23:37 +00:00
buttonSelect = std : : make_shared < CButton > ( Point ( 411 , 80 ) , AnimationPath : : builtin ( " GSPBUTT.DEF " ) , LIBRARY - > generaltexth - > zelp [ 45 ] , 0 , EShortcut : : LOBBY_SELECT_SCENARIO ) ;
2025-03-01 10:25:33 +00:00
buttonSelect - > addCallback ( [ this ] ( )
2018-01-05 20:21:07 +03:00
{
toggleTab ( tabSel ) ;
2024-05-11 13:09:40 +00:00
if ( getMapInfo ( ) & & getMapInfo ( ) - > isRandomMap )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . setMapInfo ( tabSel - > getSelectedMapInfo ( ) ) ;
2018-01-05 20:21:07 +03:00
} ) ;
2025-02-14 16:23:37 +00:00
buttonOptions = std : : make_shared < CButton > ( Point ( 411 , 510 ) , AnimationPath : : builtin ( " GSPBUTT.DEF " ) , LIBRARY - > generaltexth - > zelp [ 46 ] , std : : bind ( & CLobbyScreen : : toggleTab , this , tabOpt ) , EShortcut : : LOBBY_ADDITIONAL_OPTIONS ) ;
2023-11-13 19:49:41 +02:00
if ( settings [ " general " ] [ " enableUiEnhancements " ] . Bool ( ) )
2023-12-28 19:41:01 +01:00
{
2025-02-14 16:23:37 +00:00
buttonTurnOptions = std : : make_shared < CButton > ( Point ( 619 , 105 ) , AnimationPath : : builtin ( " GSPBUT2.DEF " ) , LIBRARY - > generaltexth - > zelp [ 46 ] , std : : bind ( & CLobbyScreen : : toggleTab , this , tabTurnOptions ) , EShortcut : : LOBBY_TURN_OPTIONS ) ;
buttonExtraOptions = std : : make_shared < CButton > ( Point ( 619 , 510 ) , AnimationPath : : builtin ( " GSPBUT2.DEF " ) , LIBRARY - > generaltexth - > zelp [ 46 ] , std : : bind ( & CLobbyScreen : : toggleTab , this , tabExtraOptions ) , EShortcut : : LOBBY_EXTRA_OPTIONS ) ;
2023-12-28 19:41:01 +01:00
}
2018-01-05 20:21:07 +03:00
} ;
2025-02-14 16:23:37 +00:00
buttonChat = std : : make_shared < CButton > ( Point ( 619 , 80 ) , AnimationPath : : builtin ( " GSPBUT2.DEF " ) , LIBRARY - > generaltexth - > zelp [ 48 ] , std : : bind ( & CLobbyScreen : : toggleChat , this ) , EShortcut : : LOBBY_TOGGLE_CHAT ) ;
buttonChat - > setTextOverlay ( LIBRARY - > generaltexth - > allTexts [ 532 ] , FONT_SMALL , Colors : : WHITE ) ;
2018-01-05 20:21:07 +03:00
switch ( screenType )
{
case ESelectionScreen : : newGame :
{
tabOpt = std : : make_shared < OptionsTab > ( ) ;
2023-11-09 16:41:00 +02:00
tabTurnOptions = std : : make_shared < TurnOptionsTab > ( ) ;
2023-12-28 19:41:01 +01:00
tabExtraOptions = std : : make_shared < ExtraOptionsTab > ( ) ;
2018-01-05 20:21:07 +03:00
tabRand = std : : make_shared < RandomMapTab > ( ) ;
2025-02-11 15:23:33 +00:00
tabRand - > mapInfoChanged + = std : : bind ( & IServerAPI : : setMapInfo , & GAME - > server ( ) , _1 , _2 ) ;
2025-02-14 16:23:37 +00:00
buttonRMG = std : : make_shared < CButton > ( Point ( 411 , 105 ) , AnimationPath : : builtin ( " GSPBUTT.DEF " ) , LIBRARY - > generaltexth - > zelp [ 47 ] , 0 , EShortcut : : LOBBY_RANDOM_MAP ) ;
2024-04-26 16:51:40 +03:00
buttonRMG - > addCallback ( [ this ] ( )
2018-01-05 20:21:07 +03:00
{
toggleTab ( tabRand ) ;
2024-05-11 13:09:40 +00:00
if ( getMapInfo ( ) & & ! getMapInfo ( ) - > isRandomMap )
2024-04-26 16:51:40 +03:00
tabRand - > updateMapInfoByHost ( ) ;
2018-01-05 20:21:07 +03:00
} ) ;
2025-02-11 15:23:33 +00:00
card - > iconDifficulty - > addCallback ( std : : bind ( & IServerAPI : : setDifficulty , & GAME - > server ( ) , _1 ) ) ;
2018-01-05 20:21:07 +03:00
2025-02-14 16:23:37 +00:00
buttonStart = std : : make_shared < CButton > ( Point ( 411 , 535 ) , AnimationPath : : builtin ( " SCNRBEG.DEF " ) , LIBRARY - > generaltexth - > zelp [ 103 ] , std : : bind ( & CLobbyScreen : : startScenario , this , false ) , EShortcut : : LOBBY_BEGIN_STANDARD_GAME ) ;
2018-01-05 20:21:07 +03:00
initLobby ( ) ;
break ;
}
case ESelectionScreen : : loadGame :
{
tabOpt = std : : make_shared < OptionsTab > ( ) ;
2023-11-09 16:41:00 +02:00
tabTurnOptions = std : : make_shared < TurnOptionsTab > ( ) ;
2023-12-28 19:41:01 +01:00
tabExtraOptions = std : : make_shared < ExtraOptionsTab > ( ) ;
2025-02-14 16:23:37 +00:00
buttonStart = std : : make_shared < CButton > ( Point ( 411 , 535 ) , AnimationPath : : builtin ( " SCNRLOD.DEF " ) , LIBRARY - > generaltexth - > zelp [ 103 ] , std : : bind ( & CLobbyScreen : : startScenario , this , false ) , EShortcut : : LOBBY_LOAD_GAME ) ;
2018-01-05 20:21:07 +03:00
initLobby ( ) ;
break ;
}
case ESelectionScreen : : campaignList :
2025-02-11 15:23:33 +00:00
tabSel - > callOnSelect = std : : bind ( & IServerAPI : : setMapInfo , & GAME - > server ( ) , _1 , nullptr ) ;
2024-04-20 15:43:39 +02:00
buttonStart = std : : make_shared < CButton > ( Point ( 411 , 535 ) , AnimationPath : : builtin ( " SCNRLOD.DEF " ) , CButton : : tooltip ( ) , std : : bind ( & CLobbyScreen : : startCampaign , this ) , EShortcut : : LOBBY_BEGIN_CAMPAIGN ) ;
2018-01-05 20:21:07 +03:00
break ;
}
2023-09-11 19:39:32 +03:00
buttonStart - > block ( true ) ; // to be unblocked after map list is ready
2025-02-14 16:23:37 +00:00
buttonBack = std : : make_shared < CButton > ( Point ( 581 , 535 ) , AnimationPath : : builtin ( " SCNRBACK.DEF " ) , LIBRARY - > generaltexth - > zelp [ 105 ] , [ & ] ( )
2018-07-25 01:36:48 +03:00
{
2025-02-11 15:23:33 +00:00
bool wasInLobbyRoom = GAME - > server ( ) . inLobbyRoom ( ) ;
GAME - > server ( ) . sendClientDisconnecting ( ) ;
2018-07-25 01:36:48 +03:00
close ( ) ;
2024-03-26 23:51:42 +02:00
if ( wasInLobbyRoom )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . getGlobalLobby ( ) . activateInterface ( ) ;
2023-04-27 20:21:06 +03:00
} , EShortcut : : GLOBAL_CANCEL ) ;
2024-12-27 21:22:45 +01:00
2024-12-27 21:40:09 +01:00
if ( hideScreen ) // workaround to avoid confusing players by custom campaign list displaying for a few ms -> instead of this draw a black screen while "loading"
2024-12-27 21:22:45 +01:00
{
blackScreen = std : : make_shared < GraphicalPrimitiveCanvas > ( Rect ( Point ( 0 , 0 ) , pos . dimensions ( ) ) ) ;
blackScreen - > addBox ( Point ( 0 , 0 ) , pos . dimensions ( ) , Colors : : BLACK ) ;
}
2018-01-05 20:21:07 +03:00
}
CLobbyScreen : : ~ CLobbyScreen ( )
{
// TODO: For now we always destroy whole lobby when leaving bonus selection screen
2025-02-11 15:23:33 +00:00
if ( GAME - > server ( ) . getState ( ) = = EClientState : : LOBBY_CAMPAIGN )
GAME - > server ( ) . sendClientDisconnecting ( ) ;
2018-01-05 20:21:07 +03:00
}
void CLobbyScreen : : toggleTab ( std : : shared_ptr < CIntObject > tab )
{
if ( tab = = curTab )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . sendGuiAction ( LobbyGuiAction : : NO_TAB ) ;
2018-01-05 20:21:07 +03:00
else if ( tab = = tabOpt )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . sendGuiAction ( LobbyGuiAction : : OPEN_OPTIONS ) ;
2018-01-05 20:21:07 +03:00
else if ( tab = = tabSel )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . sendGuiAction ( LobbyGuiAction : : OPEN_SCENARIO_LIST ) ;
2018-01-05 20:21:07 +03:00
else if ( tab = = tabRand )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . sendGuiAction ( LobbyGuiAction : : OPEN_RANDOM_MAP_OPTIONS ) ;
2023-12-20 23:52:39 +02:00
else if ( tab = = tabTurnOptions )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . sendGuiAction ( LobbyGuiAction : : OPEN_TURN_OPTIONS ) ;
2023-12-28 19:41:01 +01:00
else if ( tab = = tabExtraOptions )
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . sendGuiAction ( LobbyGuiAction : : OPEN_EXTRA_OPTIONS ) ;
2018-01-05 20:21:07 +03:00
CSelectionBase : : toggleTab ( tab ) ;
}
void CLobbyScreen : : startCampaign ( )
{
2025-02-11 15:23:33 +00:00
if ( ! GAME - > server ( ) . mi )
2024-01-24 13:44:22 +02:00
return ;
try {
2025-02-11 15:23:33 +00:00
auto ourCampaign = CampaignHandler : : getCampaign ( GAME - > server ( ) . mi - > fileURI ) ;
GAME - > server ( ) . setCampaignState ( ourCampaign ) ;
2018-01-05 20:21:07 +03:00
}
2024-01-24 13:44:22 +02:00
catch ( const std : : runtime_error & e )
{
// handle possible exception on map loading. For example campaign that contains map in unsupported format
// for example, wog campaigns or hota campaigns without hota map support mod
MetaString message ;
message . appendTextID ( " vcmi.client.errors.invalidMap " ) ;
message . replaceRawString ( e . what ( ) ) ;
CInfoWindow : : showInfoDialog ( message . toString ( ) , { } ) ;
}
2018-01-05 20:21:07 +03:00
}
void CLobbyScreen : : startScenario ( bool allowOnlyAI )
{
2025-02-11 15:23:33 +00:00
if ( tabRand & & GAME - > server ( ) . si - > mapGenOptions )
2024-02-29 12:45:08 +01:00
{
// Save RMG settings at game start
2025-02-11 15:23:33 +00:00
tabRand - > saveOptions ( * GAME - > server ( ) . si - > mapGenOptions ) ;
2024-02-29 12:45:08 +01:00
}
2024-03-01 10:57:48 +01:00
// Save chosen difficulty
Settings lastDifficulty = settings . write [ " general " ] [ " lastDifficulty " ] ;
lastDifficulty - > Integer ( ) = getCurrentDifficulty ( ) ;
2025-02-11 15:23:33 +00:00
if ( GAME - > server ( ) . validateGameStart ( allowOnlyAI ) )
2018-01-05 20:21:07 +03:00
{
2025-02-11 15:23:33 +00:00
GAME - > server ( ) . sendStartGame ( allowOnlyAI ) ;
2018-01-05 20:21:07 +03:00
buttonStart - > block ( true ) ;
}
}
void CLobbyScreen : : toggleMode ( bool host )
{
tabSel - > toggleMode ( ) ;
buttonStart - > block ( ! host ) ;
if ( screenType = = ESelectionScreen : : campaignList )
return ;
auto buttonColor = host ? Colors : : WHITE : Colors : : ORANGE ;
2025-02-14 16:23:37 +00:00
buttonSelect - > setTextOverlay ( " " + LIBRARY - > generaltexth - > allTexts [ 500 ] , FONT_SMALL , buttonColor ) ;
buttonOptions - > setTextOverlay ( LIBRARY - > generaltexth - > allTexts [ 501 ] , FONT_SMALL , buttonColor ) ;
2023-11-13 19:49:41 +02:00
if ( buttonTurnOptions )
2025-02-14 16:23:37 +00:00
buttonTurnOptions - > setTextOverlay ( LIBRARY - > generaltexth - > translate ( " vcmi.optionsTab.turnOptions.hover " ) , FONT_SMALL , buttonColor ) ;
2023-11-13 19:49:41 +02:00
2023-12-28 19:41:01 +01:00
if ( buttonExtraOptions )
2025-02-14 16:23:37 +00:00
buttonExtraOptions - > setTextOverlay ( LIBRARY - > generaltexth - > translate ( " vcmi.optionsTab.extraOptions.hover " ) , FONT_SMALL , buttonColor ) ;
2023-12-28 19:41:01 +01:00
2018-01-05 20:21:07 +03:00
if ( buttonRMG )
{
2025-02-14 16:23:37 +00:00
buttonRMG - > setTextOverlay ( " " + LIBRARY - > generaltexth - > allTexts [ 740 ] , FONT_SMALL , buttonColor ) ;
2018-01-05 20:21:07 +03:00
buttonRMG - > block ( ! host ) ;
}
buttonSelect - > block ( ! host ) ;
buttonOptions - > block ( ! host ) ;
2023-11-13 19:49:41 +02:00
if ( buttonTurnOptions )
buttonTurnOptions - > block ( ! host ) ;
2018-01-05 20:21:07 +03:00
2023-12-28 19:41:01 +01:00
if ( buttonExtraOptions )
buttonExtraOptions - > block ( ! host ) ;
2025-02-11 15:23:33 +00:00
if ( GAME - > server ( ) . mi )
2023-11-09 16:41:00 +02:00
{
2018-01-05 20:21:07 +03:00
tabOpt - > recreate ( ) ;
2023-11-09 16:41:00 +02:00
tabTurnOptions - > recreate ( ) ;
2023-12-28 19:41:01 +01:00
tabExtraOptions - > recreate ( ) ;
2023-11-09 16:41:00 +02:00
}
2018-01-05 20:21:07 +03:00
}
void CLobbyScreen : : toggleChat ( )
{
card - > toggleChat ( ) ;
if ( card - > showChat )
2025-02-14 16:23:37 +00:00
buttonChat - > setTextOverlay ( LIBRARY - > generaltexth - > allTexts [ 531 ] , FONT_SMALL , Colors : : WHITE ) ;
2018-01-05 20:21:07 +03:00
else
2025-02-14 16:23:37 +00:00
buttonChat - > setTextOverlay ( LIBRARY - > generaltexth - > allTexts [ 532 ] , FONT_SMALL , Colors : : WHITE ) ;
2018-01-05 20:21:07 +03:00
}
void CLobbyScreen : : updateAfterStateChange ( )
{
2025-02-11 15:23:33 +00:00
if ( GAME - > server ( ) . isHost ( ) & & screenType = = ESelectionScreen : : newGame )
2024-05-14 00:33:30 +02:00
{
2025-02-11 15:23:33 +00:00
bool isMultiplayer = GAME - > server ( ) . loadMode = = ELoadMode : : MULTI ;
2024-05-14 00:33:30 +02:00
ExtraOptionsInfo info = SEL - > getStartInfo ( ) - > extraOptionsInfo ;
info . cheatsAllowed = isMultiplayer ? persistentStorage [ " startExtraOptions " ] [ " multiPlayer " ] [ " cheatsAllowed " ] . Bool ( ) : ! persistentStorage [ " startExtraOptions " ] [ " singlePlayer " ] [ " cheatsNotAllowed " ] . Bool ( ) ;
info . unlimitedReplay = persistentStorage [ " startExtraOptions " ] [ isMultiplayer ? " multiPlayer " : " singlePlayer " ] [ " unlimitedReplay " ] . Bool ( ) ;
2025-02-11 15:23:33 +00:00
if ( info . cheatsAllowed ! = GAME - > server ( ) . si - > extraOptionsInfo . cheatsAllowed | | info . unlimitedReplay ! = GAME - > server ( ) . si - > extraOptionsInfo . unlimitedReplay )
GAME - > server ( ) . setExtraOptionsInfo ( info ) ;
2024-05-14 00:33:30 +02:00
}
2025-02-11 15:23:33 +00:00
if ( GAME - > server ( ) . mi )
2023-11-09 16:41:00 +02:00
{
if ( tabOpt )
tabOpt - > recreate ( ) ;
if ( tabTurnOptions )
2023-12-28 19:41:01 +01:00
tabTurnOptions - > recreate ( ) ;
if ( tabExtraOptions )
tabExtraOptions - > recreate ( ) ;
2023-11-09 16:41:00 +02:00
}
2018-01-05 20:21:07 +03:00
2025-02-11 15:23:33 +00:00
buttonStart - > block ( GAME - > server ( ) . mi = = nullptr | | GAME - > server ( ) . isGuest ( ) ) ;
2023-09-11 19:39:32 +03:00
2018-01-05 20:21:07 +03:00
card - > changeSelection ( ) ;
2020-01-21 01:09:08 -08:00
if ( card - > iconDifficulty )
{
if ( screenType = = ESelectionScreen : : loadGame )
{
// When loading the game, only one button in the difficulty toggle group should be enabled, so here disable all other buttons first, then make selection
2025-02-11 15:23:33 +00:00
card - > iconDifficulty - > setSelectedOnly ( GAME - > server ( ) . si - > difficulty ) ;
2020-01-21 01:09:08 -08:00
}
else
{
2025-02-11 15:23:33 +00:00
card - > iconDifficulty - > setSelected ( GAME - > server ( ) . si - > difficulty ) ;
2020-01-21 01:09:08 -08:00
}
}
2025-02-11 15:23:33 +00:00
if ( curTab & & curTab = = tabRand & & GAME - > server ( ) . si - > mapGenOptions )
tabRand - > setMapGenOptions ( GAME - > server ( ) . si - > mapGenOptions ) ;
2018-01-05 20:21:07 +03:00
}
const StartInfo * CLobbyScreen : : getStartInfo ( )
{
2025-02-11 15:23:33 +00:00
return GAME - > server ( ) . si . get ( ) ;
2018-01-05 20:21:07 +03:00
}
const CMapInfo * CLobbyScreen : : getMapInfo ( )
{
2025-02-11 15:23:33 +00:00
return GAME - > server ( ) . mi . get ( ) ;
2018-01-05 20:21:07 +03:00
}