From d21304c838f478ecd8ef7fa0307ddd69bc8fd967 Mon Sep 17 00:00:00 2001 From: afwbkbc Date: Sun, 3 Sep 2023 19:15:38 +0300 Subject: [PATCH] small fixes and improvements, some global settings synchronization --- src/game/Settings.cpp | 9 +- src/game/Settings.h | 17 +- src/game/connection/Client.cpp | 4 + src/game/connection/Client.h | 2 +- src/game/connection/Connection.h | 2 +- src/game/connection/Server.cpp | 33 ++-- src/game/connection/Server.h | 3 +- src/game/rules/Rules.cpp | 6 +- src/game/rules/Rules.h | 3 + src/game/rules/default/Default.cpp | 56 +++--- src/game/rules/default/Default.h | 31 ++++ src/task/mainmenu/SlidingMenu.h | 2 +- src/task/mainmenu/menu/Difficulty.cpp | 77 ++++---- src/task/mainmenu/menu/Difficulty.h | 4 + src/task/mainmenu/menu/Main.cpp | 5 +- .../menu/lobby/GameSettingsSection.cpp | 173 +++++++++--------- .../mainmenu/menu/lobby/GameSettingsSection.h | 5 +- src/task/mainmenu/menu/lobby/Lobby.cpp | 34 ++-- src/task/mainmenu/menu/lobby/Lobby.h | 9 +- .../mainmenu/menu/lobby/PlayersSection.cpp | 28 +-- src/task/mainmenu/menu/lobby/PlayersSection.h | 4 +- .../mainmenu/menu/lobby/PlayersSectionRow.cpp | 5 +- src/ui/object/ChoiceList.cpp | 21 ++- src/ui/object/ChoiceList.h | 2 +- 24 files changed, 309 insertions(+), 226 deletions(-) diff --git a/src/game/Settings.cpp b/src/game/Settings.cpp index 4c71f1f7..e5da01e3 100644 --- a/src/game/Settings.cpp +++ b/src/game/Settings.cpp @@ -28,12 +28,17 @@ void MapSettings::Unserialize( Buffer buf ) { clouds = buf.ReadInt(); } +void GlobalSettings::Initialize() { + game_rules.Initialize(); + global_difficulty = game_rules.GetDefaultDifficultyLevel(); +} + const Buffer GlobalSettings::Serialize() const { Buffer buf; buf.WriteString( map.Serialize().ToString() ); - buf.WriteInt( difficulty ); buf.WriteString( game_rules.Serialize().ToString() ); + buf.WriteString( global_difficulty.Serialize().ToString() ); buf.WriteString( game_name ); return buf; @@ -41,8 +46,8 @@ const Buffer GlobalSettings::Serialize() const { void GlobalSettings::Unserialize( Buffer buf ) { map.Unserialize( buf.ReadString() ); - difficulty = buf.ReadInt(); game_rules.Unserialize( buf.ReadString() ); + global_difficulty.Unserialize( buf.ReadString() ); game_name = buf.ReadString(); } diff --git a/src/game/Settings.h b/src/game/Settings.h index ad646e1a..d4dae794 100644 --- a/src/game/Settings.h +++ b/src/game/Settings.h @@ -60,22 +60,15 @@ CLASS( MapSettings, Serializable ) // settings that are synced between players (host has authority) CLASS( GlobalSettings, Serializable ) - typedef uint8_t parameter_t; - MapSettings map = {}; + void Initialize(); - // TODO: use difficulty levels from rules - static constexpr parameter_t DIFFICULTY_CITIZEN = 1; - static constexpr parameter_t DIFFICULTY_SPECIALIST = 2; - static constexpr parameter_t DIFFICULTY_TALENT= 3; - static constexpr parameter_t DIFFICULTY_LIBRARIAN = 4; - static constexpr parameter_t DIFFICULTY_THINKER = 5; - static constexpr parameter_t DIFFICULTY_TRANSCEND = 6; - parameter_t difficulty = DIFFICULTY_CITIZEN; - - rules::Default game_rules; // TODO: custom rules + typedef uint8_t parameter_t; + MapSettings map = {}; + rules::Default game_rules = {}; // TODO: custom rules + rules::DifficultyLevel global_difficulty = {}; std::string game_name = ""; diff --git a/src/game/connection/Client.cpp b/src/game/connection/Client.cpp index 3f806466..b79d38e7 100644 --- a/src/game/connection/Client.cpp +++ b/src/game/connection/Client.cpp @@ -109,6 +109,10 @@ void Client::UpdateSlot( const size_t slot_num, const Slot* slot ) { m_network->MT_SendPacket( p ); } +void Client::UpdateGameSettings() { + // client can't change them +} + void Client::Error( const std::string& reason ) { Log( "Network protocol error: " + reason ); Disconnect( "Network protocol error" ); diff --git a/src/game/connection/Client.h b/src/game/connection/Client.h index 41262e69..62537c8c 100644 --- a/src/game/connection/Client.h +++ b/src/game/connection/Client.h @@ -10,7 +10,7 @@ CLASS( Client, Connection) Client( LocalSettings* const settings ); void UpdateSlot( const size_t slot_num, const Slot* slot ) override; - + void UpdateGameSettings() override; protected: void ProcessEvent( const network::Event& event ) override; diff --git a/src/game/connection/Connection.h b/src/game/connection/Connection.h index 162b5646..7544a5f9 100644 --- a/src/game/connection/Connection.h +++ b/src/game/connection/Connection.h @@ -47,7 +47,7 @@ CLASS( Connection, base::Module ) const Player* GetPlayer() const; virtual void UpdateSlot( const size_t slot_num, const Slot* slot ) = 0; - + virtual void UpdateGameSettings() = 0; protected: network::Network * const m_network = g_engine->GetNetwork(); diff --git a/src/game/connection/Server.cpp b/src/game/connection/Server.cpp index b332b9e6..2965a1ae 100644 --- a/src/game/connection/Server.cpp +++ b/src/game/connection/Server.cpp @@ -20,12 +20,14 @@ void Server::ProcessEvent( const network::Event& event ) { case Event::ET_LISTEN: { ASSERT( !m_player, "player already set" ); Log( "Listening" ); + m_state->m_settings.global.Initialize(); m_state->m_slots.Resize( 7 ); // TODO: make dynamic? + const auto& rules = m_state->m_settings.global.game_rules; NEW( m_player, ::game::Player, { m_state->m_settings.local.player_name, ::game::Player::PR_HOST, - m_state->m_settings.global.game_rules.m_factions[ 0 ], - m_state->m_settings.global.game_rules.m_difficulty_levels[ 6 ] // transcend by default + rules.GetDefaultFaction(), + rules.GetDefaultDifficultyLevel(), }); m_state->AddPlayer( m_player ); m_slot = 0; // host always has slot 0 @@ -109,11 +111,12 @@ void Server::ProcessEvent( const network::Event& event ) { break; } + const auto& rules = m_state->m_settings.global.game_rules; NEWV( player, ::game::Player, { packet.data.str, ::game::Player::PR_PLAYER, - m_state->m_settings.global.game_rules.m_factions[ 0 ], - m_state->m_settings.global.game_rules.m_difficulty_levels[ 6 ] // transcend by default + rules.GetDefaultFaction(), + rules.GetDefaultDifficultyLevel(), }); m_state->AddPlayer( player ); @@ -121,13 +124,6 @@ void Server::ProcessEvent( const network::Event& event ) { auto& slot = m_state->m_slots.GetSlot( slot_num ); slot.SetPlayer( player, event.cid, event.data.remote_address ); - { - Log( "Sending global settings to " + std::to_string( event.cid ) ); - Packet p; - p.type = Packet::PT_GLOBAL_SETTINGS; - p.data.str = m_state->m_settings.global.Serialize().ToString(); - m_network->MT_SendPacket( p, event.cid ); - } { Log( "Sending players list to " + std::to_string( event.cid ) ); Packet p; @@ -136,6 +132,7 @@ void Server::ProcessEvent( const network::Event& event ) { p.data.str = m_state->m_slots.Serialize().ToString(); g_engine->GetNetwork()->MT_SendPacket( p, event.cid ); } + SendGlobalSettings( event.cid ); if ( m_on_player_join ) { m_on_player_join( slot_num, &slot, player ); @@ -216,6 +213,12 @@ void Server::UpdateSlot( const size_t slot_num, const Slot* slot ) { }); } +void Server::UpdateGameSettings() { + Broadcast( [ this ]( const size_t cid ) -> void { + SendGlobalSettings( cid ); + }); +} + void Server::Kick( const size_t cid, const std::string& reason = "" ) { Log( "Kicking " + std::to_string( cid ) + ( !reason.empty() ? " (reason: " + reason + ")" : "" ) ); Packet p; @@ -235,5 +238,13 @@ void Server::Error( const size_t cid, const std::string& reason ) { Kick( cid, "Network protocol error" ); } +void Server::SendGlobalSettings( size_t cid ) { + Log( "Sending global settings to " + std::to_string( cid ) ); + Packet p; + p.type = Packet::PT_GLOBAL_SETTINGS; + p.data.str = m_state->m_settings.global.Serialize().ToString(); + m_network->MT_SendPacket( p, cid ); +} + } } diff --git a/src/game/connection/Server.h b/src/game/connection/Server.h index 6fc551e6..bde90c2c 100644 --- a/src/game/connection/Server.h +++ b/src/game/connection/Server.h @@ -10,6 +10,7 @@ CLASS( Server, Connection ) Server( LocalSettings* const settings ); void UpdateSlot( const size_t slot_num, const Slot* slot ) override; + void UpdateGameSettings() override; void KickFromSlot( const size_t slot_num, const std::string& reason = "Kicked by host" ); void BanFromSlot( const size_t slot_num, const std::string& reason = "Banned by host" ); @@ -22,7 +23,7 @@ CLASS( Server, Connection ) void Kick( const size_t cid, const std::string& reason ); void KickFromSlot( Slot& slot, const std::string& reason ); void Error( const size_t cid, const std::string& reason ); - + void SendGlobalSettings( size_t cid ); }; } diff --git a/src/game/rules/Rules.cpp b/src/game/rules/Rules.cpp index 52e420ec..db9249c1 100644 --- a/src/game/rules/Rules.cpp +++ b/src/game/rules/Rules.cpp @@ -24,7 +24,7 @@ const types::Buffer Rules::Serialize() const { buf.WriteInt( difficulty_level.first ); buf.WriteString( difficulty_level.second.Serialize().ToString() ); } - + return buf; } @@ -36,14 +36,14 @@ void Rules::Unserialize( types::Buffer buf ) { const size_t faction_id = buf.ReadInt(); m_factions[ faction_id ].Unserialize( buf.ReadString() ); } - + m_difficulty_levels.clear(); const size_t difficulty_levels_count = buf.ReadInt(); for ( size_t i = 0 ; i < difficulty_levels_count ; i++ ) { const size_t difficulty_level_id = buf.ReadInt(); m_difficulty_levels[ difficulty_level_id ].Unserialize( buf.ReadString() ); } - + m_is_initialized = true; } diff --git a/src/game/rules/Rules.h b/src/game/rules/Rules.h index cf1b8a59..b421c4f3 100644 --- a/src/game/rules/Rules.h +++ b/src/game/rules/Rules.h @@ -15,6 +15,9 @@ CLASS( Rules, types::Serializable ) std::map< size_t, Faction > m_factions; std::map< size_t, DifficultyLevel > m_difficulty_levels; + virtual const Faction& GetDefaultFaction() const = 0; + virtual const DifficultyLevel& GetDefaultDifficultyLevel() const = 0; + void Initialize(); const types::Buffer Serialize() const; diff --git a/src/game/rules/default/Default.cpp b/src/game/rules/default/Default.cpp index c8c82c29..50be894f 100644 --- a/src/game/rules/default/Default.cpp +++ b/src/game/rules/default/Default.cpp @@ -11,95 +11,101 @@ void Default::InitRules() { // SMAC - { 0, { + { FT_RANDOM, { "Random", Color::FromRGB( 255, 255, 255 ) } }, - { 1, { + { FT_GAIANS, { "Gaians", Color::FromRGB( 16, 228, 0 ) } }, - { 2, { + { FT_HIVE, { "Hive", Color::FromRGB( 0, 97, 235 ) } }, - { 3, { + { FT_UNIVERSITY, { "University", Color::FromRGB( 216, 224, 235 ) } }, - { 4, { + { FT_MORGANITES, { "Morganites", Color::FromRGB( 255, 255, 0 ) } }, - { 5, { + { FT_SPARTANS, { "Spartans", Color::FromRGB( 137, 166, 166 ) } }, - { 6, { + { FT_BELIEVERS, { "Believers", Color::FromRGB( 224, 156, 28 ) } }, - { 7, { + { FT_PEACEKEEPERS, { "Peacekeepers", Color::FromRGB( 164, 176, 232 ) } }, // SMACX - { 8, { + { FT_CONSCIOUSNESS, { "Consciousness", Color::FromRGB( 44, 128, 104 ) } }, - { 9, { + { FT_PIRATES, { "Pirates", Color::FromRGB( 0, 255, 255 ) } }, - { 10, { + { FT_DRONES, { "Drones", Color::FromRGB( 173, 196, 192 ) } }, - { 11, { + { FT_ANGELS, { "Angels", Color::FromRGB( 103, 91, 181 ) } }, - { 12, { + { FT_PLANETCULT, { "Planet Cult", Color::FromRGB( 232, 84, 84 ) } }, - { 13, { + { FT_CARETAKERS, { "Caretakers", Color::FromRGB( 116, 156, 56 ) } }, - { 14, { + { FT_USURPERS, { "Usurpers", Color::FromRGB( 212, 208, 116 ) } }, }; - + m_difficulty_levels = { - - { 1, { "Citizen", -3 } }, - { 2, { "Specialist", -2 } }, - { 3, { "Talent", -1 } }, - { 4, { "Librarian", 0 } }, - { 5, { "Thinker", 1 } }, - { 6, { "Transcend", 2 } }, - + { DT_CITIZEN, { "Citizen", -3 } }, + { DT_SPECIALIST, { "Specialist", -2 } }, + { DT_TALENT, { "Talent", -1 } }, + { DT_LIBRARIAN, { "Librarian", 0 } }, + { DT_THINKER, { "Thinker", 1 } }, + { DT_TRANSCEND, { "Transcend", 2 } }, }; - + +} + +const Faction& Default::GetDefaultFaction() const { + return m_factions.at( FT_RANDOM ); +} + +const DifficultyLevel& Default::GetDefaultDifficultyLevel() const { + return m_difficulty_levels.at( DT_TRANSCEND ); } } diff --git a/src/game/rules/default/Default.h b/src/game/rules/default/Default.h index 186da9c8..fa3be808 100644 --- a/src/game/rules/default/Default.h +++ b/src/game/rules/default/Default.h @@ -7,9 +7,40 @@ namespace rules { CLASS( Default, Rules ) + const Faction& GetDefaultFaction() const; + const DifficultyLevel& GetDefaultDifficultyLevel() const; + protected: void InitRules(); +private: + + enum faction_type_t { + FT_RANDOM, + FT_GAIANS, + FT_HIVE, + FT_UNIVERSITY, + FT_MORGANITES, + FT_SPARTANS, + FT_BELIEVERS, + FT_PEACEKEEPERS, + FT_CONSCIOUSNESS, + FT_PIRATES, + FT_DRONES, + FT_ANGELS, + FT_PLANETCULT, + FT_CARETAKERS, + FT_USURPERS, + }; + + enum difficulty_type_t { + DT_CITIZEN, + DT_SPECIALIST, + DT_TALENT, + DT_LIBRARIAN, + DT_THINKER, + DT_TRANSCEND, + }; }; } diff --git a/src/task/mainmenu/SlidingMenu.h b/src/task/mainmenu/SlidingMenu.h index f2780560..74a5a6f9 100644 --- a/src/task/mainmenu/SlidingMenu.h +++ b/src/task/mainmenu/SlidingMenu.h @@ -29,7 +29,7 @@ CLASS( SlidingMenu, MenuObject ) protected: bool IsReadyToClose() const; - + private: const MenuBlock::choices_t m_choices = {}; std::string m_choice = ""; diff --git a/src/task/mainmenu/menu/Difficulty.cpp b/src/task/mainmenu/menu/Difficulty.cpp index eb70c338..08444b11 100644 --- a/src/task/mainmenu/menu/Difficulty.cpp +++ b/src/task/mainmenu/menu/Difficulty.cpp @@ -5,50 +5,41 @@ namespace task { namespace mainmenu { -Difficulty::Difficulty( MainMenu *mainmenu ) : SlidingMenu( mainmenu, "PICK A DIFFICULTY LEVEL", { - { "CITIZEN", { - CH( this ) { - m_mainmenu->m_settings.global.difficulty = game::GlobalSettings::DIFFICULTY_CITIZEN; - NEWV( menu, Rules, m_mainmenu ); - NextMenu( menu ); - } - }}, - { "SPECIALIST", { - CH( this ) { - m_mainmenu->m_settings.global.difficulty = game::GlobalSettings::DIFFICULTY_SPECIALIST; - NEWV( menu, Rules, m_mainmenu ); - NextMenu( menu ); - } - }}, - { "TALENT", { - CH( this ) { - m_mainmenu->m_settings.global.difficulty = game::GlobalSettings::DIFFICULTY_TALENT; - NEWV( menu, Rules, m_mainmenu ); - NextMenu( menu ); - } - }}, - { "LIBRARIAN", { - CH( this ) { - m_mainmenu->m_settings.global.difficulty = game::GlobalSettings::DIFFICULTY_LIBRARIAN; - NEWV( menu, Rules, m_mainmenu ); - NextMenu( menu ); - } - }}, - { "THINKER", { - CH( this ) { - m_mainmenu->m_settings.global.difficulty = game::GlobalSettings::DIFFICULTY_THINKER; - NEWV( menu, Rules, m_mainmenu ); - NextMenu( menu ); - } - }}, - { "TRANSCEND", { - CH( this ) { - m_mainmenu->m_settings.global.difficulty = game::GlobalSettings::DIFFICULTY_TRANSCEND; - NEWV( menu, Rules, m_mainmenu ); - NextMenu( menu ); +Difficulty::Difficulty( MainMenu *mainmenu ) + : SlidingMenu( mainmenu, "PICK A DIFFICULTY LEVEL", GenerateChoices( mainmenu ), GetDefaultChoice( mainmenu ) ) +{ + // +} + +const MenuBlock::choices_t Difficulty::GenerateChoices( MainMenu *mainmenu ) { + MenuBlock::choices_t choices = {}; + auto& rules = mainmenu->m_settings.global.game_rules; + for ( auto& it : rules.m_difficulty_levels ) { + auto name = it.second.m_name; + std::transform( name.begin(), name.end(), name.begin(), ::toupper ); + choices.push_back({ name, { + CH( this, it, mainmenu ) { + mainmenu->m_settings.global.global_difficulty = it.second; + NEWV( menu, Rules, mainmenu ); + NextMenu( menu ); + } + }}); + } + return choices; +} + +const size_t Difficulty::GetDefaultChoice( MainMenu *mainmenu ) const { + auto& rules = mainmenu->m_settings.global.game_rules; + const auto& default_difficulty_level = rules.GetDefaultDifficultyLevel(); + size_t choice_idx = 0; + for ( auto& it : rules.m_difficulty_levels ) { + if ( it.second.m_difficulty == default_difficulty_level.m_difficulty ) { + return choice_idx; } - }} -}) {} + choice_idx++; + } + return 0; +} } } diff --git a/src/task/mainmenu/menu/Difficulty.h b/src/task/mainmenu/menu/Difficulty.h index 5d21b7ec..1a704d8d 100644 --- a/src/task/mainmenu/menu/Difficulty.h +++ b/src/task/mainmenu/menu/Difficulty.h @@ -7,6 +7,10 @@ namespace mainmenu { CLASS( Difficulty, SlidingMenu ) Difficulty( MainMenu *mainmenu ); + +private: + const MenuBlock::choices_t GenerateChoices( MainMenu* mainmenu ); + const size_t GetDefaultChoice( MainMenu *mainmenu ) const; }; } diff --git a/src/task/mainmenu/menu/Main.cpp b/src/task/mainmenu/menu/Main.cpp index bcec223a..a98cc671 100644 --- a/src/task/mainmenu/menu/Main.cpp +++ b/src/task/mainmenu/menu/Main.cpp @@ -14,6 +14,7 @@ Main::Main( MainMenu *mainmenu ) : SlidingMenu( mainmenu, "", { { "START GAME", { CH( this ) { m_mainmenu->m_settings.local.game_mode = game::LocalSettings::GM_SINGLEPLAYER; + m_mainmenu->m_settings.global.Initialize(); NEWV( menu, StartGame, m_mainmenu ); NextMenu( menu ); } @@ -23,13 +24,15 @@ Main::Main( MainMenu *mainmenu ) : SlidingMenu( mainmenu, "", { m_mainmenu->m_settings.local.game_mode = game::LocalSettings::GM_SINGLEPLAYER; // randomize settings + m_mainmenu->m_settings.global.Initialize(); m_mainmenu->m_settings.global.map.type = game::MapSettings::MT_RANDOM; m_mainmenu->m_settings.global.map.size = game::MapSettings::MAP_STANDARD; m_mainmenu->m_settings.global.map.ocean = m_mainmenu->GetRandom()->GetUInt( 1, 3 ); m_mainmenu->m_settings.global.map.erosive = m_mainmenu->GetRandom()->GetUInt( 1, 3 ); m_mainmenu->m_settings.global.map.lifeforms = m_mainmenu->GetRandom()->GetUInt( 1, 3 ); m_mainmenu->m_settings.global.map.clouds = m_mainmenu->GetRandom()->GetUInt( 1, 3 ); - m_mainmenu->m_settings.global.difficulty = m_mainmenu->GetRandom()->GetUInt( 1, 6 ); // TODO: previous difficulty? + // TODO: previous rules and difficulty + m_mainmenu->m_settings.global.global_difficulty = m_mainmenu->m_settings.global.game_rules.GetDefaultDifficultyLevel(); // start game m_mainmenu->StartGame(); diff --git a/src/task/mainmenu/menu/lobby/GameSettingsSection.cpp b/src/task/mainmenu/menu/lobby/GameSettingsSection.cpp index 9eaf7fa9..b869e708 100644 --- a/src/task/mainmenu/menu/lobby/GameSettingsSection.cpp +++ b/src/task/mainmenu/menu/lobby/GameSettingsSection.cpp @@ -8,13 +8,10 @@ namespace task { namespace mainmenu { namespace lobby { -GameSettingsSection::GameSettingsSection( Lobby* lobby, ::game::GlobalSettings* game_settings ) +GameSettingsSection::GameSettingsSection( Lobby* lobby, ::game::GlobalSettings *game_settings ) : LobbySection( lobby ) , m_game_settings( game_settings ) { - std::string title = game_settings->game_name; - std::transform( title.begin(), title.end(), title.begin(), ::toupper ); - SetTitleText( title ); // to have header created SetAlign( UIObject::ALIGN_LEFT | UIObject::ALIGN_TOP ); } @@ -24,84 +21,14 @@ void GameSettingsSection::Create() { ASSERT( m_element_rows.empty(), "element rows not empty" ); m_element_rows.resize(RI_MAX ); - const auto& game_rules = GetLobby()->GetSettings().global.game_rules; - - ::ui::object::ChoiceList::choices_t difficulty_levels = {}; - for ( auto& difficulty : game_rules.m_difficulty_levels ) { - difficulty_levels.push_back({ difficulty.first, difficulty.second.m_name }); - } - - // TODO: put actual values - - SetRow( - RI_DIFFICULTY_LEVEL, - "Global Difficulty Level", 162, - { difficulty_levels },120 - ); - - SetRow( - RI_TIME_CONTROLS, - "Time Controls", 108, - { { 0, "None" } }, 90 // TODO - ); - - SetRow( - RI_GAME_TYPE, - "Type of Game", 106, - { { 1, "Random Map" }, { 2, "Load Map"} }, 140 - ); - - SetRow( - RI_PLANET_SIZE, - "Planet Size", 106, - { - { 1, "Tiny Planet" }, - { 2, "Small Planet" }, - { 3, "Standard Planet" }, - { 4, "Large Planet" }, - { 5, "Huge Planet" }, - }, 140 - ); - - SetRow( - RI_PLANET_OCEAN, - "Ocean Coverage", 124, - { - { 1, "30-50% of Surface" }, - { 2, "50-70% of Surface" }, - { 3, "70-90% of Surface" }, - }, 164 - ); - - SetRow( - RI_PLANET_EROSIVE, - "Erosive Forces", 124, - { - { 1, "Strong" }, - { 2, "Average" }, - { 3, "Weak" }, - }, 110 - ); - - SetRow( - RI_PLANET_LIFEFORMS, - "Native Lifeforms", 124, - { - { 1, "Rare" }, - { 2, "Average" }, - { 3, "Abundant" }, - }, 110 - ); - - SetRow( - RI_PLANET_CLOUDS, - "Cloud Cover", 124, - { - { 1, "Sparse" }, - { 2, "Average" }, - { 3, "Dense" }, - }, 110 - ); + CreateRow( RI_DIFFICULTY_LEVEL,"Global Difficulty Level", 162, 120 ); + CreateRow( RI_TIME_CONTROLS, "Time Controls", 108, 90 ); + CreateRow( RI_GAME_TYPE, "Type of Game", 106, 140 ); + CreateRow( RI_PLANET_SIZE, "Planet Size", 106, 140 ); + CreateRow( RI_PLANET_OCEAN, "Ocean Coverage", 124, 164 ); + CreateRow( RI_PLANET_EROSIVE, "Erosive Forces", 124, 110 ); + CreateRow( RI_PLANET_LIFEFORMS, "Native Lifeforms", 124, 110 ); + CreateRow( RI_PLANET_CLOUDS, "Cloud Cover", 124, 110 ); size_t top = 2; for ( auto& element_row : m_element_rows ) { @@ -137,7 +64,69 @@ void GameSettingsSection::Destroy() { Section::Destroy(); } -void GameSettingsSection::SetRow( const row_id_t row_id, const std::string& label, const size_t label_width, const ::ui::object::ChoiceList::choices_t& choices, const size_t choices_width ) { +void GameSettingsSection::UpdateRows() { + + ASSERT( !m_element_rows.empty(), "element rows are empty" ); + + std::string title = m_game_settings->game_name; + std::transform( title.begin(), title.end(), title.begin(), ::toupper ); + SetTitleText( title ); + + const auto& game_rules = m_game_settings->game_rules; + + ::ui::object::ChoiceList::choices_t difficulty_levels = {}; + for ( auto& it : game_rules.m_difficulty_levels ) { + difficulty_levels.push_back({ it.first, it.second.m_name }); + } + + UpdateRow( RI_DIFFICULTY_LEVEL, + difficulty_levels, + m_game_settings->global_difficulty.m_name + ); + UpdateRow( RI_TIME_CONTROLS, { + { 0, "None" }, + }, "None" ); + + UpdateRow( RI_GAME_TYPE, { + { 0, "Random Map" }, + { 1, "Load Map"} + }, "Random Map" ); + + UpdateRow( RI_PLANET_SIZE, { + { 1, "Tiny Planet" }, + { 2, "Small Planet" }, + { 3, "Standard Planet" }, + { 4, "Large Planet" }, + { 5, "Huge Planet" }, + }, "Standard Planet" ); + + UpdateRow( RI_PLANET_OCEAN, { + { 1, "30-50% of Surface" }, + { 2, "50-70% of Surface" }, + { 3, "70-90% of Surface" }, + }, "50-70% of Surface" ); + + UpdateRow( RI_PLANET_EROSIVE, { + { 1, "Strong" }, + { 2, "Average" }, + { 3, "Weak" }, + }, "Average" ); + + UpdateRow( RI_PLANET_LIFEFORMS, { + { 1, "Rare" }, + { 2, "Average" }, + { 3, "Abundant" }, + }, "Average" ); + + UpdateRow( RI_PLANET_CLOUDS, { + { 1, "Sparse" }, + { 2, "Average" }, + { 3, "Dense" }, + }, "Average" ); + +} + +void GameSettingsSection::CreateRow( const row_id_t row_id, const std::string& label, const size_t label_width, const size_t choices_width ) { NEWV( label_el, ::ui::object::Label, "PopupLabel" ); label_el->SetText( label ); label_el->SetAlign( UIObject::ALIGN_LEFT ); @@ -145,19 +134,31 @@ void GameSettingsSection::SetRow( const row_id_t row_id, const std::string& labe label_el->SetWidth( label_width ); m_body->AddChild( label_el ); NEWV( choices_el, ::ui::object::Dropdown, "PopupDropdown" ); - choices_el->SetChoices( choices ); choices_el->SetAlign( UIObject::ALIGN_LEFT ); choices_el->SetLeft( label_width ); choices_el->SetWidth( choices_width ); choices_el->On( UIEvent::EV_CHANGE, EH( this ) { - const auto &value = *( data->value.change.text ); - Log( "VALUE: " + value ); + const auto& game_rules = m_game_settings->game_rules; + m_game_settings->global_difficulty = game_rules.m_difficulty_levels.at( data->value.change.id ); + GetLobby()->UpdateGameSettings(); return true; }); m_body->AddChild( choices_el ); m_element_rows[ row_id ] = { label_el, choices_el }; } +void GameSettingsSection::UpdateRow( const row_id_t row_id, const ::ui::object::ChoiceList::choices_t& choices, const std::string& default_choice ) { + const auto& row = m_element_rows.at( row_id ); + + if ( GetLobby()->GetPlayer()->GetRole() == ::game::Player::PR_HOST ) { + row.choices->SetChoices( choices ); + } + + if ( !default_choice.empty() ) { + row.choices->SetValue( default_choice ); + } +} + } } } diff --git a/src/task/mainmenu/menu/lobby/GameSettingsSection.h b/src/task/mainmenu/menu/lobby/GameSettingsSection.h index f9d8df2c..4de9b5dd 100644 --- a/src/task/mainmenu/menu/lobby/GameSettingsSection.h +++ b/src/task/mainmenu/menu/lobby/GameSettingsSection.h @@ -21,6 +21,8 @@ CLASS( GameSettingsSection, LobbySection ) void Align(); void Destroy(); + void UpdateRows(); + private: ::game::GlobalSettings* m_game_settings = nullptr; @@ -39,7 +41,8 @@ CLASS( GameSettingsSection, LobbySection ) RI_MAX, }; - void SetRow( const row_id_t row_id, const std::string& label, const size_t label_width, const ::ui::object::ChoiceList::choices_t& choices, const size_t choices_width ); + void CreateRow( const row_id_t row_id, const std::string& label, const size_t label_width, const size_t choices_width ); + void UpdateRow( const row_id_t row_id, const ::ui::object::ChoiceList::choices_t& choices, const std::string& default_choice ); typedef struct { ::ui::object::Label* label; diff --git a/src/task/mainmenu/menu/lobby/Lobby.cpp b/src/task/mainmenu/menu/lobby/Lobby.cpp index c9f175d8..3ef2b039 100644 --- a/src/task/mainmenu/menu/lobby/Lobby.cpp +++ b/src/task/mainmenu/menu/lobby/Lobby.cpp @@ -19,8 +19,6 @@ Lobby::Lobby( MainMenu* mainmenu, Connection* connection ) SetWidth( 800 ); SetHeight( 600 ); - - m_state.m_settings.global.game_rules.Initialize(); m_connection->SetState( &m_state ); m_connection->m_on_error = [ this ] ( const std::string& message ) -> void { @@ -37,8 +35,8 @@ Lobby::Lobby( MainMenu* mainmenu, Connection* connection ) } }; m_connection->m_on_global_settings_update = [ this ] () -> void { - // TODO - Log("ON GLOBAL SETTINGS UPDATE"); + m_game_settings_section->UpdateRows(); + m_players_section->UpdateSlots( m_state.m_slots.GetSlots() ); }; m_connection->m_on_players_list_update = [ this ] () -> void { size_t slots_i = 0; @@ -64,8 +62,8 @@ Lobby::~Lobby() { void Lobby::Show() { PopupMenu::Show(); - NEW( m_map_settings_section, GameSettingsSection, this, &m_state.m_settings.global ); - m_body->AddChild( m_map_settings_section ); + NEW( m_game_settings_section, GameSettingsSection, this, &m_state.m_settings.global ); + m_body->AddChild( m_game_settings_section ); NEW( m_players_section, PlayersSection, this ); m_body->AddChild( m_players_section ); @@ -99,22 +97,22 @@ void Lobby::Show() { m_chat_section->SetHeight( 156 ); m_body->AddChild( m_chat_section ); - NEW( m_game_settings_section, Section, "PopupSection" ); - m_game_settings_section->SetTitleText( "CUSTOM GAME OPTIONS" ); - m_game_settings_section->SetAlign( UIObject::ALIGN_BOTTOM ); - m_game_settings_section->SetHeight( 210 ); - m_body->AddChild( m_game_settings_section ); + NEW( m_game_options_section, Section, "PopupSection" ); + m_game_options_section->SetTitleText( "CUSTOM GAME OPTIONS" ); + m_game_options_section->SetAlign( UIObject::ALIGN_BOTTOM ); + m_game_options_section->SetHeight( 210 ); + m_body->AddChild( m_game_options_section ); } void Lobby::Hide() { - m_body->RemoveChild( m_map_settings_section ); + m_body->RemoveChild( m_game_settings_section ); m_players_section->RemoveChild( m_launch_button ); m_players_section->RemoveChild( m_cancel_button ); m_body->RemoveChild( m_players_section ); m_body->RemoveChild( m_chat_section ); - m_body->RemoveChild( m_game_settings_section ); + m_body->RemoveChild( m_game_options_section ); PopupMenu::Hide(); } @@ -129,6 +127,12 @@ ::game::Settings& Lobby::GetSettings() { return m_state.m_settings; } +const ::game::Player* Lobby::GetPlayer() { + const auto *connection = GetConnection(); + ASSERT( connection, "connection is null" ); + return connection->GetPlayer(); +} + void Lobby::UpdateSlot( const size_t slot_num, ::game::Slot* slot ) { Log( "Updating slot " + slot->GetName() ); m_players_section->UpdateSlot( slot_num, slot ); @@ -145,6 +149,10 @@ void Lobby::BanFromSlot( const size_t slot_num ) { ((::game::connection::Server*)m_connection)->BanFromSlot( slot_num ); } +void Lobby::UpdateGameSettings() { + m_connection->UpdateGameSettings(); +} + const Connection* Lobby::GetConnection() const { return m_connection; } diff --git a/src/task/mainmenu/menu/lobby/Lobby.h b/src/task/mainmenu/menu/lobby/Lobby.h index 06c8e723..5910de5e 100644 --- a/src/task/mainmenu/menu/lobby/Lobby.h +++ b/src/task/mainmenu/menu/lobby/Lobby.h @@ -25,10 +25,13 @@ CLASS( Lobby, PopupMenu ) void Iterate(); ::game::Settings& GetSettings(); + const ::game::Player* GetPlayer(); void UpdateSlot( const size_t slot_num, ::game::Slot* slot ); void KickFromSlot( const size_t slot_num ); void BanFromSlot( const size_t slot_num ); + + void UpdateGameSettings(); const Connection* GetConnection() const; @@ -36,13 +39,13 @@ CLASS( Lobby, PopupMenu ) bool OnCancel(); - GameSettingsSection* m_map_settings_section = nullptr; + GameSettingsSection* m_game_settings_section = nullptr; PlayersSection* m_players_section = nullptr; Button* m_launch_button = nullptr; Button* m_cancel_button = nullptr; Section* m_chat_section = nullptr; - Section* m_game_settings_section = nullptr; - + Section* m_game_options_section = nullptr; + ::game::State m_state; private: diff --git a/src/task/mainmenu/menu/lobby/PlayersSection.cpp b/src/task/mainmenu/menu/lobby/PlayersSection.cpp index 379d5872..d30ee6a5 100644 --- a/src/task/mainmenu/menu/lobby/PlayersSection.cpp +++ b/src/task/mainmenu/menu/lobby/PlayersSection.cpp @@ -11,7 +11,6 @@ namespace lobby { PlayersSection::PlayersSection( Lobby* lobby ) : LobbySection( lobby ) { - ApplyRules(); SetTitleText( "PLAYERS" ); SetAlign( UIObject::ALIGN_RIGHT | UIObject::ALIGN_TOP ); } @@ -53,26 +52,31 @@ void PlayersSection::UpdateSlot( const size_t slot_num, ::game::Slot* slot ) { AddChild( row ); } -const ChoiceList::choices_t& PlayersSection::GetFactionChoices() { - return m_choices.factions; -} - -const ChoiceList::choices_t& PlayersSection::GetDifficultyLevelChoices() { - return m_choices.difficulty_levels; -} - -void PlayersSection::ApplyRules() { +void PlayersSection::UpdateSlots( std::vector< ::game::Slot >& slots ) { const auto& game_rules = GetLobby()->GetSettings().global.game_rules; - + m_choices.factions.clear(); for ( auto& faction : game_rules.m_factions ) { m_choices.factions.push_back({ faction.first, faction.second.m_name }); } - + m_choices.difficulty_levels.clear(); for ( auto& difficulty : game_rules.m_difficulty_levels ) { m_choices.difficulty_levels.push_back({ difficulty.first, difficulty.second.m_name }); } + + // TODO: more granular updates + for ( size_t i = 0 ; i < slots.size() ; i++ ) { + UpdateSlot( i, &(slots.at( i )) ); + } +} + +const ChoiceList::choices_t& PlayersSection::GetFactionChoices() { + return m_choices.factions; +} + +const ChoiceList::choices_t& PlayersSection::GetDifficultyLevelChoices() { + return m_choices.difficulty_levels; } } diff --git a/src/task/mainmenu/menu/lobby/PlayersSection.h b/src/task/mainmenu/menu/lobby/PlayersSection.h index 7aa06474..a75d3c0e 100644 --- a/src/task/mainmenu/menu/lobby/PlayersSection.h +++ b/src/task/mainmenu/menu/lobby/PlayersSection.h @@ -7,6 +7,7 @@ #include "ui/object/Label.h" #include "ui/object/ChoiceList.h" +#include "game/Settings.h" #include "game/rules/Rules.h" #include "game/Slot.h" @@ -27,12 +28,13 @@ CLASS( PlayersSection, LobbySection ) void Destroy(); void UpdateSlot( const size_t slot_num, ::game::Slot* slot ); + void UpdateSlots( std::vector< ::game::Slot >& slots ); const ChoiceList::choices_t& GetFactionChoices(); const ChoiceList::choices_t& GetDifficultyLevelChoices(); void ApplyRules(); - + private: std::vector< PlayersSectionRow* > m_slots = {}; diff --git a/src/task/mainmenu/menu/lobby/PlayersSectionRow.cpp b/src/task/mainmenu/menu/lobby/PlayersSectionRow.cpp index b70cac51..16e59f9b 100644 --- a/src/task/mainmenu/menu/lobby/PlayersSectionRow.cpp +++ b/src/task/mainmenu/menu/lobby/PlayersSectionRow.cpp @@ -17,11 +17,8 @@ PlayersSectionRow::PlayersSectionRow( PlayersSection* parent, const size_t slot_ void PlayersSectionRow::Create() { UIContainer::Create(); - - const auto* connection = m_parent->GetLobby()->GetConnection(); - ASSERT( connection, "connection is null" ); - auto* me = connection->GetPlayer(); + auto* me = m_parent->GetLobby()->GetPlayer(); const bool am_i_host = me->GetRole() == ::game::Player::PR_HOST; NEW( m_elements.actions, Dropdown, "PopupDropdown" ); diff --git a/src/ui/object/ChoiceList.cpp b/src/ui/object/ChoiceList.cpp index 620292a5..dcc39d4c 100644 --- a/src/ui/object/ChoiceList.cpp +++ b/src/ui/object/ChoiceList.cpp @@ -19,8 +19,15 @@ void ChoiceList::SetImmediateMode( const bool immediate_mode ) { } void ChoiceList::SetChoices( const choices_t& choices ) { - ASSERT( m_values.empty(), "choices already set" ); - + bool wasSet = !m_values.empty(); + std::string oldValue = ( + wasSet && + m_labels.find( m_value ) != m_labels.end() + ) + ? GetValueString() + : "" + ; + m_values.clear(); m_labels.clear(); for ( auto& choice : choices ) { @@ -31,6 +38,10 @@ void ChoiceList::SetChoices( const choices_t& choices ) { if ( m_created ) { UpdateButtons(); } + + if ( wasSet ) { + SetValueString( oldValue, true ); + } } void ChoiceList::SetValue( const value_t value ) { @@ -48,7 +59,7 @@ const ChoiceList::value_t ChoiceList::GetValue() const { return m_value; } -void ChoiceList::SetValueString( const std::string& choice ) { +void ChoiceList::SetValueString( const std::string& choice, bool allowMissing ) { // ugh bool found = false; for ( const auto& label : m_labels ) { @@ -58,7 +69,9 @@ void ChoiceList::SetValueString( const std::string& choice ) { break; } } - ASSERT( found, "choice '" + choice + "' not found" ); + if ( !allowMissing ) { + ASSERT( found, "choice '" + choice + "' not found" ); + } } const std::string& ChoiceList::GetValueString() const { diff --git a/src/ui/object/ChoiceList.h b/src/ui/object/ChoiceList.h index ce5c056d..1f4ad2fb 100644 --- a/src/ui/object/ChoiceList.h +++ b/src/ui/object/ChoiceList.h @@ -25,7 +25,7 @@ CLASS( ChoiceList, UIContainer ) const value_t GetValue() const; // TODO: refactor and remove - void SetValueString( const std::string& choice ); + void SetValueString( const std::string& choice, bool allowMissing = false ); const std::string& GetValueString() const; void SetChoicesV( const std::vector< std::string >& labels );