2018-01-05 20:21:07 +03:00
/*
* RandomMapTab . 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 "RandomMapTab.h"
# include "CSelectionBase.h"
2023-10-21 02:12:34 +02:00
# include "CLobbyScreen.h"
# include "SelectionTab.h"
2018-01-05 20:21:07 +03: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-05-18 23:31:05 +03:00
# include "../gui/MouseButton.h"
2023-05-16 15:10:26 +03:00
# include "../gui/WindowHandler.h"
2025-11-13 02:14:42 +01:00
# include "../gui/Shortcut.h"
2018-01-05 20:21:07 +03:00
# include "../widgets/CComponent.h"
2023-08-25 14:07:38 +04:00
# include "../widgets/ComboBox.h"
2018-01-05 20:21:07 +03:00
# include "../widgets/Buttons.h"
# include "../widgets/MiscWidgets.h"
# include "../widgets/ObjectLists.h"
2023-05-30 17:31:45 +03:00
# include "../widgets/Slider.h"
2018-01-05 20:21:07 +03:00
# include "../widgets/TextControls.h"
2025-11-13 02:14:42 +01:00
# include "../widgets/GraphicalPrimitiveCanvas.h"
# include "../widgets/CTextInput.h"
2018-01-05 20:21:07 +03:00
# include "../windows/GUIClasses.h"
# include "../windows/InfoWindows.h"
2024-07-20 12:55:17 +00:00
# include "../../lib/texts/CGeneralTextHandler.h"
2018-01-05 20:21:07 +03:00
# include "../../lib/mapping/CMapInfo.h"
2023-05-24 02:05:59 +03:00
# include "../../lib/mapping/CMapHeader.h"
2023-05-24 01:14:06 +03:00
# include "../../lib/mapping/MapFormat.h"
2018-01-05 20:21:07 +03:00
# include "../../lib/rmg/CMapGenOptions.h"
2022-12-13 04:38:18 +04:00
# include "../../lib/rmg/CRmgTemplateStorage.h"
2023-03-15 21:34:29 +02:00
# include "../../lib/filesystem/Filesystem.h"
2023-01-11 15:17:24 +02:00
# include "../../lib/RoadHandler.h"
2018-01-05 20:21:07 +03:00
2024-02-29 12:45:08 +01:00
# include "../../lib/CConfigHandler.h"
# include "../../lib/serializer/JsonSerializer.h"
# include "../../lib/serializer/JsonDeserializer.h"
2022-12-12 03:27:59 +04:00
RandomMapTab : : RandomMapTab ( ) :
2025-10-08 01:12:57 +02:00
InterfaceObjectConfigurable ( ) ,
templateIndex ( 0 )
2018-01-05 20:21:07 +03:00
{
recActions = 0 ;
mapGenOptions = std : : make_shared < CMapGenOptions > ( ) ;
2022-12-12 03:27:59 +04:00
2025-11-13 02:14:42 +01:00
addCallback ( " toggleMapSize " , [ this ] ( int btnId )
2018-01-05 20:21:07 +03:00
{
2025-11-18 21:46:03 +01:00
onToggleMapSize ( btnId ) ;
2018-01-05 20:21:07 +03:00
} ) ;
2022-12-12 03:27:59 +04:00
addCallback ( " toggleTwoLevels " , [ & ] ( bool on )
2018-01-05 20:21:07 +03:00
{
2025-11-13 02:14:42 +01:00
mapGenOptions - > setLevels ( on ? 2 : 1 ) ;
2022-12-14 05:23:21 +04:00
if ( mapGenOptions - > getMapTemplate ( ) )
2025-08-01 00:37:32 +02:00
if ( ! mapGenOptions - > getMapTemplate ( ) - > matchesSize ( int3 { mapGenOptions - > getWidth ( ) , mapGenOptions - > getHeight ( ) , mapGenOptions - > getLevels ( ) } ) )
2022-12-14 05:23:21 +04:00
setTemplate ( nullptr ) ;
2018-01-05 20:21:07 +03:00
updateMapInfoByHost ( ) ;
} ) ;
2022-12-12 03:27:59 +04:00
addCallback ( " setPlayersCount " , [ & ] ( int btnId )
2018-01-05 20:21:07 +03:00
{
2023-10-28 20:30:38 +02:00
mapGenOptions - > setHumanOrCpuPlayerCount ( btnId ) ;
2022-12-14 04:37:11 +04:00
setMapGenOptions ( mapGenOptions ) ;
2018-01-05 20:21:07 +03:00
updateMapInfoByHost ( ) ;
} ) ;
2022-12-12 03:27:59 +04:00
addCallback ( " setTeamsCount " , [ & ] ( int btnId )
2018-01-05 20:21:07 +03:00
{
mapGenOptions - > setTeamCount ( btnId ) ;
updateMapInfoByHost ( ) ;
} ) ;
2022-12-12 03:27:59 +04:00
addCallback ( " setCompOnlyPlayers " , [ & ] ( int btnId )
2018-01-05 20:21:07 +03:00
{
mapGenOptions - > setCompOnlyPlayerCount ( btnId ) ;
2022-12-14 04:37:11 +04:00
setMapGenOptions ( mapGenOptions ) ;
2018-01-05 20:21:07 +03:00
updateMapInfoByHost ( ) ;
} ) ;
2022-12-12 03:27:59 +04:00
addCallback ( " setCompOnlyTeams " , [ & ] ( int btnId )
2018-01-05 20:21:07 +03:00
{
mapGenOptions - > setCompOnlyTeamCount ( btnId ) ;
updateMapInfoByHost ( ) ;
} ) ;
2022-12-12 03:27:59 +04:00
addCallback ( " setWaterContent " , [ & ] ( int btnId )
2018-01-05 20:21:07 +03:00
{
mapGenOptions - > setWaterContent ( static_cast < EWaterContent : : EWaterContent > ( btnId ) ) ;
updateMapInfoByHost ( ) ;
} ) ;
2022-12-12 03:27:59 +04:00
2022-12-12 11:38:27 +04:00
addCallback ( " setMonsterStrength " , [ & ] ( int btnId )
2018-01-05 20:21:07 +03:00
{
if ( btnId < 0 )
mapGenOptions - > setMonsterStrength ( EMonsterStrength : : RANDOM ) ;
else
2018-08-24 13:37:05 +02:00
mapGenOptions - > setMonsterStrength ( static_cast < EMonsterStrength : : EMonsterStrength > ( btnId ) ) ; //value 2 to 4
2018-01-05 20:21:07 +03:00
updateMapInfoByHost ( ) ;
} ) ;
2022-12-12 03:27:59 +04:00
2022-12-13 03:47:29 +04:00
//new callbacks available only from mod
2022-12-16 00:46:36 +04:00
addCallback ( " teamAlignments " , [ & ] ( int )
{
2025-02-10 21:49:23 +00:00
ENGINE - > windows ( ) . createAndPushWindow < TeamAlignments > ( * this ) ;
2022-12-16 00:46:36 +04:00
} ) ;
2025-02-14 16:23:37 +00:00
for ( const auto & road : LIBRARY - > roadTypeHandler - > objects )
2022-12-16 00:46:36 +04:00
{
2023-01-01 22:42:28 +02:00
std : : string cbRoadType = " selectRoad_ " + road - > getJsonKey ( ) ;
2024-05-16 22:05:51 +00:00
addCallback ( cbRoadType , [ & , roadID = road - > getId ( ) ] ( bool on )
2022-12-16 00:46:36 +04:00
{
2024-05-16 22:05:51 +00:00
mapGenOptions - > setRoadEnabled ( roadID , on ) ;
2022-12-17 04:54:37 +04:00
updateMapInfoByHost ( ) ;
2022-12-16 00:46:36 +04:00
} ) ;
}
2023-09-02 00:26:14 +03:00
const JsonNode config ( JsonPath : : builtin ( " config/widgets/randomMapTab.json " ) ) ;
2022-12-25 14:22:07 +04:00
build ( config ) ;
2022-12-12 03:27:59 +04:00
2023-10-21 02:12:34 +02:00
if ( auto w = widget < CButton > ( " buttonShowRandomMaps " ) )
{
w - > addCallback ( [ & ] ( )
{
( static_cast < CLobbyScreen * > ( parent ) ) - > toggleTab ( ( static_cast < CLobbyScreen * > ( parent ) ) - > tabSel ) ;
( static_cast < CLobbyScreen * > ( parent ) ) - > tabSel - > showRandom = true ;
( static_cast < CLobbyScreen * > ( parent ) ) - > tabSel - > filter ( 0 , true ) ;
} ) ;
}
2023-08-25 14:07:38 +04:00
//set combo box callbacks
if ( auto w = widget < ComboBox > ( " templateList " ) )
{
2025-10-09 00:01:00 +02:00
auto getTemplates = [ ] ( ) {
2025-02-14 16:23:37 +00:00
auto templates = LIBRARY - > tplh - > getTemplates ( ) ;
2023-08-25 14:07:38 +04:00
boost : : range : : sort ( templates , [ ] ( const CRmgTemplate * a , const CRmgTemplate * b ) {
return a - > getName ( ) < b - > getName ( ) ;
} ) ;
2025-10-09 00:01:00 +02:00
return templates ;
} ;
2023-08-25 14:07:38 +04:00
2025-10-09 00:01:00 +02:00
w - > onConstructItems = [ getTemplates ] ( std : : vector < const void * > & curItems ) {
2023-08-25 14:07:38 +04:00
curItems . push_back ( nullptr ) ; //default template
2025-10-09 00:01:00 +02:00
for ( auto & t : getTemplates ( ) )
2023-08-25 14:07:38 +04:00
curItems . push_back ( t ) ;
} ;
w - > onSetItem = [ & ] ( const void * item ) {
this - > setTemplate ( reinterpret_cast < const CRmgTemplate * > ( item ) ) ;
} ;
w - > getItemText = [ this ] ( int idx , const void * item ) {
if ( item )
return reinterpret_cast < const CRmgTemplate * > ( item ) - > getName ( ) ;
if ( idx = = 0 )
return readText ( variables [ " randomTemplate " ] ) ;
return std : : string ( " " ) ;
} ;
2025-10-08 01:12:57 +02:00
2025-10-09 00:01:00 +02:00
w - > addCallback ( [ this , getTemplates ] ( ) // no real dropdown... - instead open dialog
2025-10-08 01:12:57 +02:00
{
std : : vector < std : : string > texts ;
texts . push_back ( readText ( variables [ " randomTemplate " ] ) ) ;
2025-10-28 15:20:26 +01:00
auto selectedTemplate = mapGenOptions - > getMapTemplate ( ) ;
const auto & templates = getTemplates ( ) ;
for ( int i = 0 ; i < templates . size ( ) ; i + + )
{
if ( selectedTemplate )
{
if ( templates [ i ] - > getId ( ) = = selectedTemplate - > getId ( ) )
templateIndex = i + 1 ;
}
else
templateIndex = 0 ;
texts . push_back ( templates [ i ] - > getName ( ) ) ;
}
2025-10-08 01:12:57 +02:00
2025-10-09 00:01:00 +02:00
ENGINE - > windows ( ) . popWindows ( 1 ) ;
2025-10-08 01:12:57 +02:00
ENGINE - > windows ( ) . createAndPushWindow < CObjectListWindow > ( texts , nullptr , LIBRARY - > generaltexth - > translate ( " vcmi.lobby.templatesSelect.hover " ) , LIBRARY - > generaltexth - > translate ( " vcmi.lobby.templatesSelect.help " ) , [ this ] ( int index ) {
widget < ComboBox > ( " templateList " ) - > setItem ( index ) ;
2025-10-28 15:20:26 +01:00
} , templateIndex , std : : vector < std : : shared_ptr < IImage > > ( ) , true , true ) ;
2025-10-08 01:12:57 +02:00
} ) ;
2023-08-25 14:07:38 +04:00
}
2024-02-29 12:45:08 +01:00
loadOptions ( ) ;
2018-01-05 20:21:07 +03:00
}
2025-11-18 21:46:03 +01:00
void RandomMapTab : : onToggleMapSize ( int btnId )
{
if ( btnId = = - 1 )
return ;
auto mapSizeVal = getStandardMapSizes ( ) ;
auto setTemplateForSize = [ this ] ( ) {
if ( mapGenOptions - > getMapTemplate ( ) )
if ( ! mapGenOptions - > getMapTemplate ( ) - > matchesSize ( int3 { mapGenOptions - > getWidth ( ) , mapGenOptions - > getHeight ( ) , mapGenOptions - > getLevels ( ) } ) )
setTemplate ( nullptr ) ;
updateMapInfoByHost ( ) ;
} ;
if ( btnId = = mapSizeVal . size ( ) - 1 )
{
ENGINE - > windows ( ) . createAndPushWindow < SetSizeWindow > ( int3 ( mapGenOptions - > getWidth ( ) , mapGenOptions - > getHeight ( ) , mapGenOptions - > getLevels ( ) ) , [ this , setTemplateForSize ] ( int3 ret ) {
if ( ret . z > 2 )
{
std : : shared_ptr < CInfoWindow > temp = CInfoWindow : : create ( LIBRARY - > generaltexth - > translate ( " vcmi.lobby.customRmgSize.experimental " ) , PlayerColor ( 0 ) , { } ) ; //TODO: multilevel support
ENGINE - > windows ( ) . pushWindow ( temp ) ;
}
mapGenOptions - > setWidth ( ret . x ) ;
mapGenOptions - > setHeight ( ret . y ) ;
mapGenOptions - > setLevels ( ret . z ) ;
setTemplateForSize ( ) ;
} ) ;
return ;
}
mapGenOptions - > setWidth ( mapSizeVal [ btnId ] ) ;
mapGenOptions - > setHeight ( mapSizeVal [ btnId ] ) ;
setTemplateForSize ( ) ;
}
2018-01-05 20:21:07 +03:00
void RandomMapTab : : updateMapInfoByHost ( )
{
2025-02-11 15:23:33 +00:00
if ( GAME - > server ( ) . isGuest ( ) )
2018-01-05 20:21:07 +03:00
return ;
// Generate header info
mapInfo = std : : make_shared < CMapInfo > ( ) ;
mapInfo - > isRandomMap = true ;
2022-12-07 23:36:20 +02:00
mapInfo - > mapHeader = std : : make_unique < CMapHeader > ( ) ;
2023-05-20 17:34:39 +03:00
mapInfo - > mapHeader - > version = EMapFormat : : VCMI ;
2023-09-27 22:53:13 +02:00
mapInfo - > mapHeader - > name . appendLocalString ( EMetaText : : GENERAL_TXT , 740 ) ;
mapInfo - > mapHeader - > description . appendLocalString ( EMetaText : : GENERAL_TXT , 741 ) ;
2024-02-03 16:23:56 +01:00
2025-07-14 00:18:11 +03:00
if ( mapGenOptions - > getWaterContent ( ) ! = EWaterContent : : RANDOM )
mapInfo - > mapHeader - > banWaterHeroes ( mapGenOptions - > getWaterContent ( ) ! = EWaterContent : : NONE ) ;
2024-02-03 16:23:56 +01:00
const auto * temp = mapGenOptions - > getMapTemplate ( ) ;
if ( temp )
{
auto randomTemplateDescription = temp - > getDescription ( ) ;
if ( ! randomTemplateDescription . empty ( ) )
{
auto description = std : : string ( " \n \n " ) + randomTemplateDescription ;
mapInfo - > mapHeader - > description . appendRawString ( description ) ;
}
2025-07-14 00:18:11 +03:00
for ( const auto & hero : temp - > getBannedHeroes ( ) )
mapInfo - > mapHeader - > allowedHeroes . erase ( hero ) ;
2024-02-03 16:23:56 +01:00
}
2024-02-05 21:27:55 +02:00
mapInfo - > mapHeader - > difficulty = EMapDifficulty : : NORMAL ;
2018-01-05 20:21:07 +03:00
mapInfo - > mapHeader - > height = mapGenOptions - > getHeight ( ) ;
mapInfo - > mapHeader - > width = mapGenOptions - > getWidth ( ) ;
2025-08-01 00:37:32 +02:00
mapInfo - > mapHeader - > mapLevels = mapGenOptions - > getLevels ( ) ;
2018-01-05 20:21:07 +03:00
// Generate player information
2023-10-30 07:48:51 +01:00
int playersToGen = mapGenOptions - > getMaxPlayersCount ( ) ;
2020-07-07 19:45:53 +08:00
2018-01-05 20:21:07 +03:00
mapInfo - > mapHeader - > howManyTeams = playersToGen ;
2023-10-29 10:05:24 +01:00
//TODO: Assign all human-controlled colors in first place
2023-07-24 08:44:37 +02:00
2023-08-10 21:21:37 +03:00
for ( int i = 0 ; i < PlayerColor : : PLAYER_LIMIT_I ; + + i )
{
mapInfo - > mapHeader - > players [ i ] . canComputerPlay = false ;
mapInfo - > mapHeader - > players [ i ] . canHumanPlay = false ;
}
2023-10-28 20:30:38 +02:00
std : : vector < PlayerColor > availableColors ;
for ( ui8 color = 0 ; color < PlayerColor : : PLAYER_LIMIT_I ; color + + )
2018-01-05 20:21:07 +03:00
{
2023-10-28 20:30:38 +02:00
availableColors . push_back ( PlayerColor ( color ) ) ;
2018-01-05 20:21:07 +03:00
}
2023-10-28 20:30:38 +02:00
//First restore known players
for ( auto & player : mapGenOptions - > getPlayersSettings ( ) )
{
PlayerInfo playerInfo ;
2023-10-29 21:25:39 +01:00
playerInfo . isFactionRandom = ( player . second . getStartingTown ( ) = = FactionID : : RANDOM ) ;
2023-10-28 20:30:38 +02:00
playerInfo . canComputerPlay = ( player . second . getPlayerType ( ) ! = EPlayerType : : HUMAN ) ;
playerInfo . canHumanPlay = ( player . second . getPlayerType ( ) ! = EPlayerType : : COMP_ONLY ) ;
auto team = player . second . getTeam ( ) ;
playerInfo . team = team ;
playerInfo . hasMainTown = true ;
playerInfo . generateHeroAtMainTown = true ;
2025-04-19 16:12:07 +03:00
mapInfo - > mapHeader - > players [ player . first . getNum ( ) ] = playerInfo ;
2023-10-28 20:30:38 +02:00
vstd : : erase ( availableColors , player . first ) ;
}
2018-01-05 20:21:07 +03:00
mapInfoChanged ( mapInfo , mapGenOptions ) ;
}
void RandomMapTab : : setMapGenOptions ( std : : shared_ptr < CMapGenOptions > opts )
{
2022-12-14 04:37:11 +04:00
mapGenOptions = opts ;
2023-10-28 20:30:38 +02:00
//Prepare allowed options - add all, then erase the ones above the limit
2022-12-14 04:37:11 +04:00
for ( int i = 0 ; i < = PlayerColor : : PLAYER_LIMIT_I ; + + i )
{
playerCountAllowed . insert ( i ) ;
compCountAllowed . insert ( i ) ;
2023-07-20 20:34:00 +02:00
if ( i > = 2 )
{
playerTeamsAllowed . insert ( i ) ;
}
if ( i > = 1 )
{
compTeamsAllowed . insert ( i ) ;
}
2022-12-14 04:37:11 +04:00
}
2023-10-29 21:25:39 +01:00
std : : set < int > humanCountAllowed ;
2023-10-28 20:30:38 +02:00
2022-12-14 04:37:11 +04:00
auto * tmpl = mapGenOptions - > getMapTemplate ( ) ;
if ( tmpl )
{
2023-10-29 10:05:24 +01:00
playerCountAllowed = tmpl - > getPlayers ( ) . getNumbers ( ) ;
2023-10-29 21:25:39 +01:00
humanCountAllowed = tmpl - > getHumanPlayers ( ) . getNumbers ( ) ; // Unused now?
2022-12-14 04:37:11 +04:00
}
2023-10-28 20:30:38 +02:00
2024-11-24 19:50:47 -08:00
si8 playerLimit = opts - > getPlayerLimit ( ) ;
2023-10-28 20:30:38 +02:00
si8 humanOrCpuPlayerCount = opts - > getHumanOrCpuPlayerCount ( ) ;
2023-10-29 10:05:24 +01:00
si8 compOnlyPlayersCount = opts - > getCompOnlyPlayerCount ( ) ;
2023-10-28 20:30:38 +02:00
2023-10-29 10:05:24 +01:00
if ( humanOrCpuPlayerCount ! = CMapGenOptions : : RANDOM_SIZE )
2022-12-14 04:37:11 +04:00
{
2023-10-28 20:30:38 +02:00
vstd : : erase_if ( compCountAllowed , [ playerLimit , humanOrCpuPlayerCount ] ( int el )
{
return ( playerLimit - humanOrCpuPlayerCount ) < el ;
2022-12-14 04:37:11 +04:00
} ) ;
2023-10-28 20:30:38 +02:00
vstd : : erase_if ( playerTeamsAllowed , [ humanOrCpuPlayerCount ] ( int el )
{
return humanOrCpuPlayerCount < = el ;
2022-12-14 04:37:11 +04:00
} ) ;
2023-10-29 21:25:39 +01:00
}
else // Random
{
2023-10-30 21:33:49 +01:00
vstd : : erase_if ( compCountAllowed , [ playerLimit ] ( int el )
2023-10-28 20:30:38 +02:00
{
2023-10-29 21:25:39 +01:00
return ( playerLimit - 1 ) < el ; // Must leave at least 1 human player
} ) ;
vstd : : erase_if ( playerTeamsAllowed , [ playerLimit ] ( int el )
{
return playerLimit < = el ;
} ) ;
}
if ( ! playerTeamsAllowed . count ( opts - > getTeamCount ( ) ) )
{
opts - > setTeamCount ( CMapGenOptions : : RANDOM_SIZE ) ;
2022-12-14 04:37:11 +04:00
}
2023-10-29 21:25:39 +01:00
2023-10-29 10:05:24 +01:00
if ( compOnlyPlayersCount ! = CMapGenOptions : : RANDOM_SIZE )
2022-12-14 04:37:11 +04:00
{
2023-10-28 20:30:38 +02:00
// This setting doesn't impact total number of players
vstd : : erase_if ( compTeamsAllowed , [ compOnlyPlayersCount ] ( int el )
{
return compOnlyPlayersCount < = el ;
2022-12-14 04:37:11 +04:00
} ) ;
2022-12-14 05:45:50 +04:00
if ( ! compTeamsAllowed . count ( opts - > getCompOnlyTeamCount ( ) ) )
2023-10-28 20:30:38 +02:00
{
2022-12-14 05:45:50 +04:00
opts - > setCompOnlyTeamCount ( CMapGenOptions : : RANDOM_SIZE ) ;
2023-10-28 20:30:38 +02:00
}
2022-12-14 04:37:11 +04:00
}
2022-12-12 11:38:27 +04:00
if ( auto w = widget < CToggleGroup > ( " groupMapSize " ) )
2023-04-19 23:14:23 +03:00
{
2025-11-18 21:46:03 +01:00
const auto & mapSizes = getStandardMapSizes ( ) ;
2023-04-19 23:14:23 +03:00
for ( auto toggle : w - > buttons )
{
if ( auto button = std : : dynamic_pointer_cast < CToggleButton > ( toggle . second ) )
{
2025-08-01 00:37:32 +02:00
int3 size ( mapSizes [ toggle . first ] , mapSizes [ toggle . first ] , mapGenOptions - > getLevels ( ) ) ;
2023-04-19 23:14:23 +03:00
bool sizeAllowed = ! mapGenOptions - > getMapTemplate ( ) | | mapGenOptions - > getMapTemplate ( ) - > matchesSize ( size ) ;
2025-11-13 02:14:42 +01:00
button - > block ( ! sizeAllowed & & ! ( toggle . first = = mapSizes . size ( ) - 1 ) ) ;
2023-04-19 23:14:23 +03:00
}
}
2025-11-18 21:46:03 +01:00
auto position = vstd : : find_pos ( getStandardMapSizes ( ) , opts - > getWidth ( ) ) ;
2025-11-14 20:32:06 +01:00
w - > setSelected ( position = = mapSizes . size ( ) - 1 | | opts - > getWidth ( ) ! = opts - > getHeight ( ) ? - 1 : position ) ;
2023-04-19 23:14:23 +03:00
}
2022-12-12 11:38:27 +04:00
if ( auto w = widget < CToggleButton > ( " buttonTwoLevels " ) )
2023-04-19 23:14:23 +03:00
{
2025-08-29 19:46:41 +02:00
int possibleLevelCount = 2 ;
if ( mapGenOptions - > getMapTemplate ( ) )
{
auto sizes = mapGenOptions - > getMapTemplate ( ) - > getMapSizes ( ) ;
possibleLevelCount = sizes . second . z - sizes . first . z + 1 ;
}
2025-11-13 02:14:42 +01:00
w - > setSelectedSilent ( opts - > getLevels ( ) = = 2 ) ;
2025-08-29 19:46:41 +02:00
w - > block ( possibleLevelCount < 2 ) ;
2023-04-19 23:14:23 +03:00
}
2022-12-12 11:38:27 +04:00
if ( auto w = widget < CToggleGroup > ( " groupMaxPlayers " ) )
2022-12-14 04:37:11 +04:00
{
2023-10-28 20:30:38 +02:00
w - > setSelected ( opts - > getHumanOrCpuPlayerCount ( ) ) ;
2022-12-14 04:37:11 +04:00
deactivateButtonsFrom ( * w , playerCountAllowed ) ;
}
2022-12-12 11:38:27 +04:00
if ( auto w = widget < CToggleGroup > ( " groupMaxTeams " ) )
2022-12-14 04:37:11 +04:00
{
2022-12-12 03:58:39 +04:00
w - > setSelected ( opts - > getTeamCount ( ) ) ;
2022-12-14 05:23:21 +04:00
deactivateButtonsFrom ( * w , playerTeamsAllowed ) ;
2022-12-14 04:37:11 +04:00
}
2022-12-12 11:38:27 +04:00
if ( auto w = widget < CToggleGroup > ( " groupCompOnlyPlayers " ) )
2022-12-14 04:37:11 +04:00
{
2022-12-12 03:58:39 +04:00
w - > setSelected ( opts - > getCompOnlyPlayerCount ( ) ) ;
2022-12-14 05:23:21 +04:00
deactivateButtonsFrom ( * w , compCountAllowed ) ;
2022-12-14 04:37:11 +04:00
}
2022-12-12 11:38:27 +04:00
if ( auto w = widget < CToggleGroup > ( " groupCompOnlyTeams " ) )
2022-12-14 04:37:11 +04:00
{
2022-12-12 03:58:39 +04:00
w - > setSelected ( opts - > getCompOnlyTeamCount ( ) ) ;
2022-12-14 04:37:11 +04:00
deactivateButtonsFrom ( * w , compTeamsAllowed ) ;
}
2022-12-12 11:38:27 +04:00
if ( auto w = widget < CToggleGroup > ( " groupWaterContent " ) )
2022-12-14 04:37:11 +04:00
{
2022-12-12 03:58:39 +04:00
w - > setSelected ( opts - > getWaterContent ( ) ) ;
2022-12-14 04:37:11 +04:00
if ( opts - > getMapTemplate ( ) )
{
std : : set < int > allowedWater ( opts - > getMapTemplate ( ) - > getWaterContentAllowed ( ) . begin ( ) , opts - > getMapTemplate ( ) - > getWaterContentAllowed ( ) . end ( ) ) ;
deactivateButtonsFrom ( * w , allowedWater ) ;
}
else
deactivateButtonsFrom ( * w , { - 1 } ) ;
}
2022-12-12 11:38:27 +04:00
if ( auto w = widget < CToggleGroup > ( " groupMonsterStrength " ) )
2022-12-12 03:58:39 +04:00
w - > setSelected ( opts - > getMonsterStrength ( ) ) ;
2022-12-17 08:38:33 +04:00
if ( auto w = widget < CButton > ( " templateButton " ) )
{
if ( tmpl )
2024-02-27 22:19:09 +02:00
w - > setTextOverlay ( tmpl - > getName ( ) , EFonts : : FONT_SMALL , Colors : : WHITE ) ;
2022-12-17 08:38:33 +04:00
else
2024-02-27 22:19:09 +02:00
w - > setTextOverlay ( readText ( variables [ " randomTemplate " ] ) , EFonts : : FONT_SMALL , Colors : : WHITE ) ;
2022-12-17 08:38:33 +04:00
}
2025-02-14 16:23:37 +00:00
for ( const auto & r : LIBRARY - > roadTypeHandler - > objects )
2022-12-17 08:38:33 +04:00
{
2023-12-21 16:09:01 +02:00
// Workaround for vcmi-extras bug
std : : string jsonKey = r - > getJsonKey ( ) ;
std : : string identifier = jsonKey . substr ( jsonKey . find ( ' : ' ) + 1 ) ;
if ( auto w = widget < CToggleButton > ( identifier ) )
2022-12-17 08:38:33 +04:00
{
2023-07-08 08:44:10 +02:00
w - > setSelected ( opts - > isRoadEnabled ( r - > getId ( ) ) ) ;
2022-12-17 08:38:33 +04:00
}
}
2018-01-05 20:21:07 +03:00
}
2022-12-13 04:38:18 +04:00
void RandomMapTab : : setTemplate ( const CRmgTemplate * tmpl )
{
mapGenOptions - > setMapTemplate ( tmpl ) ;
2022-12-14 04:37:11 +04:00
setMapGenOptions ( mapGenOptions ) ;
2022-12-13 04:38:18 +04:00
if ( auto w = widget < CButton > ( " templateButton " ) )
{
if ( tmpl )
2024-02-27 22:19:09 +02:00
w - > setTextOverlay ( tmpl - > getName ( ) , EFonts : : FONT_SMALL , Colors : : WHITE ) ;
2022-12-13 04:38:18 +04:00
else
2024-02-27 22:19:09 +02:00
w - > setTextOverlay ( readText ( variables [ " randomTemplate " ] ) , EFonts : : FONT_SMALL , Colors : : WHITE ) ;
2022-12-13 04:38:18 +04:00
}
2022-12-14 04:37:11 +04:00
updateMapInfoByHost ( ) ;
}
void RandomMapTab : : deactivateButtonsFrom ( CToggleGroup & group , const std : : set < int > & allowed )
2018-01-05 20:21:07 +03:00
{
2022-12-14 04:37:11 +04:00
logGlobal - > debug ( " Blocking buttons " ) ;
for ( auto toggle : group . buttons )
2018-01-05 20:21:07 +03:00
{
2018-04-07 14:34:11 +03:00
if ( auto button = std : : dynamic_pointer_cast < CToggleButton > ( toggle . second ) )
2018-01-05 20:21:07 +03:00
{
2022-12-14 04:37:11 +04:00
if ( allowed . count ( CMapGenOptions : : RANDOM_SIZE )
| | allowed . count ( toggle . first )
| | toggle . first = = CMapGenOptions : : RANDOM_SIZE )
2018-01-05 20:21:07 +03:00
{
button - > block ( false ) ;
}
else
{
button - > block ( true ) ;
}
}
}
}
2025-11-18 21:46:03 +01:00
std : : vector < int > RandomMapTab : : getStandardMapSizes ( )
2018-01-05 20:21:07 +03:00
{
2022-12-12 04:46:42 +04:00
return { CMapHeader : : MAP_SIZE_SMALL , CMapHeader : : MAP_SIZE_MIDDLE , CMapHeader : : MAP_SIZE_LARGE , CMapHeader : : MAP_SIZE_XLARGE , CMapHeader : : MAP_SIZE_HUGE , CMapHeader : : MAP_SIZE_XHUGE , CMapHeader : : MAP_SIZE_GIANT } ;
2018-01-05 20:21:07 +03:00
}
2022-12-13 03:47:29 +04:00
2023-07-20 20:34:00 +02:00
void TeamAlignmentsWidget : : checkTeamCount ( )
{
//Do not allow to select one team only
std : : set < TeamID > teams ;
for ( int plId = 0 ; plId < players . size ( ) ; + + plId )
{
teams . insert ( TeamID ( players [ plId ] - > getSelected ( ) ) ) ;
}
if ( teams . size ( ) < 2 )
{
//Do not let player close the window
buttonOk - > block ( true ) ;
}
else
{
buttonOk - > block ( false ) ;
}
}
2023-10-22 15:00:04 +02:00
TeamAlignments : : TeamAlignments ( RandomMapTab & randomMapTab )
: CWindowObject ( BORDERED )
{
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2023-10-22 15:00:04 +02:00
widget = std : : make_shared < TeamAlignmentsWidget > ( randomMapTab ) ;
pos = widget - > pos ;
updateShadow ( ) ;
center ( ) ;
}
2022-12-17 03:53:26 +04:00
TeamAlignmentsWidget : : TeamAlignmentsWidget ( RandomMapTab & randomMapTab ) :
2022-12-30 01:35:16 +02:00
InterfaceObjectConfigurable ( )
2022-12-17 03:53:26 +04:00
{
2023-09-02 00:26:14 +03:00
const JsonNode config ( JsonPath : : builtin ( " config/widgets/randomMapTeamsWidget.json " ) ) ;
2022-12-17 20:38:16 +04:00
variables = config [ " variables " ] ;
2022-12-17 03:53:26 +04:00
2023-10-29 21:25:39 +01:00
//int totalPlayers = randomMapTab.obtainMapGenOptions().getPlayerLimit();
int totalPlayers = randomMapTab . obtainMapGenOptions ( ) . getMaxPlayersCount ( ) ;
2022-12-17 08:19:16 +04:00
assert ( totalPlayers < = PlayerColor : : PLAYER_LIMIT_I ) ;
2024-03-04 21:23:17 +01:00
auto playerSettings = randomMapTab . obtainMapGenOptions ( ) . getPlayersSettings ( ) ;
2022-12-17 20:38:16 +04:00
variables [ " totalPlayers " ] . Integer ( ) = totalPlayers ;
pos . w = variables [ " windowSize " ] [ " x " ] . Integer ( ) + totalPlayers * variables [ " cellMargin " ] [ " x " ] . Integer ( ) ;
2024-11-23 02:33:25 +01:00
auto widthExtend = std : : max ( pos . w , 220 ) - pos . w ; // too small for buttons
pos . w + = widthExtend ;
2022-12-17 20:38:16 +04:00
pos . h = variables [ " windowSize " ] [ " y " ] . Integer ( ) + totalPlayers * variables [ " cellMargin " ] [ " y " ] . Integer ( ) ;
2023-10-24 18:51:58 +02:00
variables [ " backgroundRect " ] [ " x " ] . Integer ( ) = 0 ;
variables [ " backgroundRect " ] [ " y " ] . Integer ( ) = 0 ;
2022-12-17 20:38:16 +04:00
variables [ " backgroundRect " ] [ " w " ] . Integer ( ) = pos . w ;
variables [ " backgroundRect " ] [ " h " ] . Integer ( ) = pos . h ;
variables [ " okButtonPosition " ] [ " x " ] . Integer ( ) = variables [ " buttonsOffset " ] [ " ok " ] [ " x " ] . Integer ( ) ;
variables [ " okButtonPosition " ] [ " y " ] . Integer ( ) = variables [ " buttonsOffset " ] [ " ok " ] [ " y " ] . Integer ( ) + totalPlayers * variables [ " cellMargin " ] [ " y " ] . Integer ( ) ;
variables [ " cancelButtonPosition " ] [ " x " ] . Integer ( ) = variables [ " buttonsOffset " ] [ " cancel " ] [ " x " ] . Integer ( ) ;
variables [ " cancelButtonPosition " ] [ " y " ] . Integer ( ) = variables [ " buttonsOffset " ] [ " cancel " ] [ " y " ] . Integer ( ) + totalPlayers * variables [ " cellMargin " ] [ " y " ] . Integer ( ) ;
addCallback ( " ok " , [ & ] ( int )
{
for ( int plId = 0 ; plId < players . size ( ) ; + + plId )
{
randomMapTab . obtainMapGenOptions ( ) . setPlayerTeam ( PlayerColor ( plId ) , TeamID ( players [ plId ] - > getSelected ( ) ) ) ;
}
randomMapTab . updateMapInfoByHost ( ) ;
2023-10-22 15:00:04 +02:00
2025-02-10 21:49:23 +00:00
for ( auto & window : ENGINE - > windows ( ) . findWindows < TeamAlignments > ( ) )
ENGINE - > windows ( ) . popWindow ( window ) ;
2022-12-17 20:38:16 +04:00
} ) ;
addCallback ( " cancel " , [ & ] ( int )
{
2025-02-10 21:49:23 +00:00
for ( auto & window : ENGINE - > windows ( ) . findWindows < TeamAlignments > ( ) )
ENGINE - > windows ( ) . popWindow ( window ) ;
2022-12-17 20:38:16 +04:00
} ) ;
2022-12-25 14:22:07 +04:00
build ( config ) ;
2022-12-17 08:19:16 +04:00
2022-12-17 03:53:26 +04:00
center ( pos ) ;
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION ;
2022-12-17 20:38:16 +04:00
2023-10-29 21:25:39 +01:00
// Window should have X * X columns, where X is max players allowed for current settings
2023-10-28 20:30:38 +02:00
// For random player count, X is 8
2024-03-04 21:23:17 +01:00
if ( totalPlayers > playerSettings . size ( ) )
2023-10-28 20:30:38 +02:00
{
auto savedPlayers = randomMapTab . obtainMapGenOptions ( ) . getSavedPlayersMap ( ) ;
for ( const auto & player : savedPlayers )
{
2024-03-04 21:23:17 +01:00
if ( ! vstd : : contains ( playerSettings , player . first ) )
2023-10-28 20:30:38 +02:00
{
2024-03-04 21:23:17 +01:00
playerSettings [ player . first ] = player . second ;
2023-10-28 20:30:38 +02:00
}
}
}
std : : vector < CMapGenOptions : : CPlayerSettings > settingsVec ;
2024-03-04 21:23:17 +01:00
for ( const auto & player : playerSettings )
2023-10-28 20:30:38 +02:00
{
settingsVec . push_back ( player . second ) ;
}
2022-12-17 08:19:16 +04:00
for ( int plId = 0 ; plId < totalPlayers ; + + plId )
{
players . push_back ( std : : make_shared < CToggleGroup > ( [ & , totalPlayers , plId ] ( int sel )
{
2022-12-17 20:38:16 +04:00
variables [ " player_id " ] . Integer ( ) = plId ;
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION_TARGETED ( players [ plId ] . get ( ) ) ;
2022-12-17 08:19:16 +04:00
for ( int teamId = 0 ; teamId < totalPlayers ; + + teamId )
{
auto button = std : : dynamic_pointer_cast < CToggleButton > ( players [ plId ] - > buttons [ teamId ] ) ;
assert ( button ) ;
if ( sel = = teamId )
{
2024-02-27 22:19:09 +02:00
button - > setOverlay ( buildWidget ( variables [ " flagsAnimation " ] ) ) ;
2022-12-17 08:19:16 +04:00
}
else
{
2024-02-27 22:19:09 +02:00
button - > setOverlay ( nullptr ) ;
2022-12-17 08:19:16 +04:00
}
2023-07-20 20:34:00 +02:00
button - > addCallback ( [ this ] ( bool )
{
checkTeamCount ( ) ;
} ) ;
2022-12-17 08:19:16 +04:00
}
} ) ) ;
2024-08-09 15:30:04 +00:00
OBJECT_CONSTRUCTION_TARGETED ( players . back ( ) . get ( ) ) ;
2023-10-28 20:30:38 +02:00
2022-12-17 08:19:16 +04:00
for ( int teamId = 0 ; teamId < totalPlayers ; + + teamId )
{
2024-11-23 02:33:25 +01:00
variables [ " point " ] [ " x " ] . Integer ( ) = variables [ " cellOffset " ] [ " x " ] . Integer ( ) + plId * variables [ " cellMargin " ] [ " x " ] . Integer ( ) + ( widthExtend / 2 ) ;
2022-12-17 20:38:16 +04:00
variables [ " point " ] [ " y " ] . Integer ( ) = variables [ " cellOffset " ] [ " y " ] . Integer ( ) + teamId * variables [ " cellMargin " ] [ " y " ] . Integer ( ) ;
auto button = buildWidget ( variables [ " button " ] ) ;
players . back ( ) - > addToggle ( teamId , std : : dynamic_pointer_cast < CToggleBase > ( button ) ) ;
2022-12-17 08:19:16 +04:00
}
2024-06-24 03:23:26 +02:00
// plId is not necessarily player color, just an index
2023-10-28 20:30:38 +02:00
auto team = settingsVec . at ( plId ) . getTeam ( ) ;
2022-12-17 08:19:16 +04:00
if ( team = = TeamID : : NO_TEAM )
2023-10-28 20:30:38 +02:00
{
logGlobal - > warn ( " Player %d (id %d) has uninitialized team " , settingsVec . at ( plId ) . getColor ( ) , plId ) ;
2022-12-17 08:19:16 +04:00
players . back ( ) - > setSelected ( plId ) ;
2023-10-28 20:30:38 +02:00
}
2022-12-17 08:19:16 +04:00
else
players . back ( ) - > setSelected ( team . getNum ( ) ) ;
}
2023-07-20 20:34:00 +02:00
buttonOk = widget < CButton > ( " buttonOK " ) ;
buttonCancel = widget < CButton > ( " buttonCancel " ) ;
2022-12-17 03:53:26 +04:00
}
2024-02-29 12:45:08 +01:00
void RandomMapTab : : saveOptions ( const CMapGenOptions & options )
{
JsonNode data ;
2024-06-27 01:26:28 +02:00
JsonSerializer ser ( nullptr , data ) ;
2024-02-29 12:45:08 +01:00
2024-06-27 01:26:28 +02:00
ser . serializeStruct ( " lastSettings " , const_cast < CMapGenOptions & > ( options ) ) ;
2024-02-29 12:45:08 +01:00
// FIXME: Do not nest fields
Settings rmgSettings = persistentStorage . write [ " rmg " ] ;
rmgSettings [ " rmg " ] = data ;
}
void RandomMapTab : : loadOptions ( )
{
2025-07-14 00:18:11 +03:00
JsonNode rmgSettings = persistentStorage [ " rmg " ] [ " rmg " ] ;
2024-02-29 12:45:08 +01:00
if ( ! rmgSettings . Struct ( ) . empty ( ) )
{
2025-07-14 00:18:11 +03:00
rmgSettings . setModScope ( ModScope : : scopeGame ( ) ) ;
2024-02-29 13:04:48 +01:00
mapGenOptions . reset ( new CMapGenOptions ( ) ) ;
2024-02-29 12:45:08 +01:00
JsonDeserializer handler ( nullptr , rmgSettings ) ;
2024-02-29 13:04:48 +01:00
handler . serializeStruct ( " lastSettings " , * mapGenOptions ) ;
2024-02-29 12:45:08 +01:00
// Will check template and set other options as well
setTemplate ( mapGenOptions - > getMapTemplate ( ) ) ;
if ( auto w = widget < ComboBox > ( " templateList " ) )
{
w - > setItem ( mapGenOptions - > getMapTemplate ( ) ) ;
}
2024-09-04 08:37:45 +09:00
} else
{
// Default settings
mapGenOptions - > setRoadEnabled ( RoadId ( Road : : DIRT_ROAD ) , true ) ;
mapGenOptions - > setRoadEnabled ( RoadId ( Road : : GRAVEL_ROAD ) , true ) ;
mapGenOptions - > setRoadEnabled ( RoadId ( Road : : COBBLESTONE_ROAD ) , true ) ;
2024-02-29 12:45:08 +01:00
}
updateMapInfoByHost ( ) ;
2024-02-29 13:04:48 +01:00
// TODO: Save & load difficulty?
2024-05-16 22:05:51 +00:00
}
2025-11-13 02:14:42 +01:00
SetSizeWindow : : SetSizeWindow ( int3 initSize , std : : function < void ( int3 ) > cb )
: CWindowObject ( BORDERED )
{
OBJECT_CONSTRUCTION ;
pos . w = 200 ;
pos . h = 122 ;
updateShadow ( ) ;
center ( ) ;
background = std : : make_shared < FilledTexturePlayerColored > ( Rect ( 0 , 0 , pos . w , pos . h ) ) ;
background - > setPlayerColor ( PlayerColor ( 1 ) ) ;
buttonOk = std : : make_shared < CButton > ( Point ( 68 , 80 ) , AnimationPath : : builtin ( " MuBchck " ) , CButton : : tooltip ( ) , [ this , cb ] ( ) {
close ( ) ;
if ( cb )
cb ( int3 ( std : : max ( 1 , std : : stoi ( numInputs [ 0 ] - > getText ( ) ) ) , std : : max ( 1 , std : : stoi ( numInputs [ 1 ] - > getText ( ) ) ) , std : : max ( 1 , std : : stoi ( numInputs [ 2 ] - > getText ( ) ) ) ) ) ;
} , EShortcut : : GLOBAL_ACCEPT ) ;
titles . push_back ( std : : make_shared < CLabel > ( 100 , 15 , FONT_BIG , ETextAlignment : : CENTER , Colors : : WHITE , LIBRARY - > generaltexth - > translate ( " vcmi.lobby.customRmgSize.title " ) ) ) ;
for ( int i = 0 ; i < 3 ; i + + )
{
Rect r ( 30 + i * 50 , 50 , 40 , 20 ) ;
rectangles . push_back ( std : : make_shared < TransparentFilledRectangle > ( r , ColorRGBA ( 0 , 0 , 0 , 128 ) , ColorRGBA ( 64 , 64 , 64 , 64 ) , 1 ) ) ;
titles . push_back ( std : : make_shared < CLabel > ( 50 + i * 50 , 40 , FONT_SMALL , ETextAlignment : : CENTER , Colors : : WHITE , LIBRARY - > generaltexth - > translate ( " vcmi.lobby.customRmgSize. " + std : : to_string ( i ) ) ) ) ;
numInputs . push_back ( std : : make_shared < CTextInput > ( r , EFonts : : FONT_SMALL , ETextAlignment : : CENTER , false ) ) ;
numInputs . back ( ) - > setFilterNumber ( 0 , i < 2 ? 999 : 9 ) ;
}
numInputs [ 0 ] - > setText ( std : : to_string ( initSize . x ) ) ;
numInputs [ 1 ] - > setText ( std : : to_string ( initSize . y ) ) ;
numInputs [ 2 ] - > setText ( std : : to_string ( initSize . z ) ) ;
}